How to safely capture both toast title and message in Playwright without waiting timeout?

I’m working with Playwright (Node.js) and need to capture notification toasts that appear on the page.
The issue is that the toasts don’t always have the same structure:

  • Some have only a message

  • Some have a title and a message

  • They also change their class (toast-info, toast-warning, toast-error, etc.)

When I try to capture both the title and the message, Playwright sometimes freezes, waiting for .toast-title when it doesn’t exist. I need a safe and generic way to capture all possible cases without running into timeouts.

<!-- example of toast with only message -->
<div id="toast-container" class="toast-top-right" aria-live="polite" role="alert">
  <div class="toast toast-info" style="display: block;">
    <button class="toast-close-button" role="button"><i class="ion-android-close"></i></button>
    <div class="toast-message">Nota Lesión Activa: Lesiones 364</div>
  </div>
</div>

<!-- example of toast with title and message -->
<div id="toast-container" class="toast-top-right" aria-live="polite" role="alert">
  <div class="toast toast-error" style="display: block;">
    <button class="toast-close-button" role="button"><i class="ion-android-close"></i></button>
    <div class="toast-title">Error</div>
    <div class="toast-message">Paciente no encontrado</div>
  </div>
</div>

Error observed

Sometimes my test fails with a timeout when trying to get the toast title:

Get text content(
page.locator('#toast-container .toast').first().locator('.toast-title')
)
— 30.0s
waiting for locator('#toast-container .toast').first().locator('.toast-title')
Timeout 30000ms exceeded.

What I tried

I created two functions: one (boton) that clicks a button and checks for toasts, and another (Capturaerror) that extracts the toast-title and toast-message.

async function boton(page, Accion, indice = 0) {
    await page.getByRole('button', { name: Accion }).nth(indice).click({ timeout: 1000 });
    const toasts = page.locator('#toast-container .toast, #toast-container .toast-error, #toast-container .toast-warning');
    const count = await toasts.count();
    const mensajes = [];

    for (let i = 0; i < count; i++) {
        const toast = toasts.nth(i);
        const clase = await toast.getAttribute('class') || '';
        const mensaje = await toast.locator('.toast-message').textContent().catch(() => '');

        if (clase.includes('toast-error')) {
            if (mensaje && mensaje.trim() !== '') {
                mensajes.push(`${i + 1}.- ${mensaje.trim()}`);
            }
        } else if (clase.includes('toast-warning')) {
            const msj = await Capturaerror(page);
            if (msj && msj.length > 0) {
                throw new Error(`${msj.join('n')}`);
            }
        } 
    }

    if (mensajes.length > 0) {
        throw new Error(mensajes.join("n"));
    }
}

async function Capturaerror(page) {
    const toasts = await page.locator('#toast-container .toast').all();
    const mensajes = [];

    let index = 1;
    for (const toast of toasts) {
        const titulo = await toast.locator('.toast-title').textContent().catch(() => '');
        const mensaje = await toast.locator('.toast-message').textContent().catch(() => '');
        if (titulo || mensaje) {
            mensajes.push(`${index}.- ${titulo.trim()}: ${mensaje.trim()}`);
            index++;
        }            
    }
    return mensajes;
}

What I expected

To always capture the visible text of each toast, regardless of whether it has a title, a message, or both.
The .catch(() => '') should skip missing .toast-title without freezing.


What actually happens

If a toast does not contain a .toast-title, Playwright waits for it until the timeout (30s), which causes the test to freeze.


Notes

  • I want a single generic solution that safely captures the title and/or message, or the whole toast text, without timeouts.

  • Node.js / Playwright environment.

usememo hook and usecallback hook

where to use usememo hook and usecallback hooks

Explanation for the Usememo and usecallback hooks and their usage and main differences between these hooks because this hooks are using for the similar usage (memoization).

LIFF getIDToken returns undefined on iOS but works on Android

I am building an application with Java Spring Boot + Jquery using LiffSDK for my chat application.

  @GetMapping
  public String init(@RequestParam String liffChannelId,
      @RequestParam String messageChannelId,
      @RequestParam String isInit,
      @RequestParam String idToken,
      HttpServletRequest request, Model model) {
    if (Objects.isNull(isInit)) {
      return "chat_ui";
    }

    ChatForm form =chatHelper.init(liffChannelId, messageChannelId, idToken, request);
    model.addAttribute("form", form);

    return "chat_ui";
  }

And in my Js:

$(document).ready(function () {
  const urlParams = new URLSearchParams(window.location.search);
  const isInit = urlParams.get("isInit");
  if (!isInit) {
    initLiffApp();
  }
});

function initLiffApp() {
  const messageChannelId = new URLSearchParams(window.location.search).get("messageChannelId");

  const liffChannelId = new URLSearchParams(window.location.search).get("liffChannelId");

  const liffId = new URLSearchParams(window.location.search).get("liffId");

  liff
    .init({
      liffId: liffId
    })
    .then(() => {
      const idToken = liff.getIDToken();
      if (!idToken) {
        alert("Failed to get ID Token");
        return;
      }
      sendToServer(liffChannelId, messageChannelId, idToken);
    })
    .catch(err => {
      console.error("LIFF error", err);
    });
}

function sendToServer(liffChannelId, messageChannelId, idToken) {
  const redirectUrl = `/chat?liffChannelId=${encodeURIComponent(liffChannelId)}&messageChannelId=${encodeURIComponent(messageChannelId)}&isInit=1&idToken=${encodeURIComponent(idToken)}`;
  window.location.href = redirectUrl;
}

The application being deployed will call the server twice. When initializing, based on whether the isInit variable is passed or not, it will return to the interface. Then in Js, it will call Liff Server to get idToken. At this time, it will call the server a second time with the isInit variable = true and then the server will continue processing.

I tested on Android and it still received normally, but on iOS it kept saying it could not get idToken and displayed an alert cannot get idToken.

Can someone help me with this problem? Thank you very much

Triggering onClick() and keyup() automatically when using an onscreen keyboards

I have two virtual key boards codes for two languages other than English. The codes are working perfectly and values of pressed keys transferred to respective input text boxes, The only problem is that functions of keyup() and OnClick() do not work until and unless enter key from manual keyboard is pressed or mouse click done into the input box. Will appreciate if following codes are amended to include in them keyup() and Click() functions, so there should be no need to manually touch any key from manual keyboard or mouse clicked into the text box. thanks.

<input type="text"  id="myInput" onkeyup="myFunction()" onClick="myFunction()" placeholder=>

//First virtual keyboard:
const urduInput = document.getElementById('myInput');
const urduKeyboard = document.getElementById('urduKeyboard');

    for (const key in urduPhoneticMap) {
        const button = document.createElement('button');
        button.className = 'keyboard-button';
        button.textContent = urduPhoneticMap[key];
        button.onclick = () => {
            if (key === 'backspace') {
                urduInput.value = urduInput.value.slice(0, -1);
            } else {
                urduInput.value += urduPhoneticMap[key];
            }
            urduInput.focus(); // Keep focus on the input field
        };
    
        urduKeyboard.appendChild(button);
    
}

// Here it is needed to add some code like ((document.getElementById("myInput").click();)) to make input box clicked automatically plus a similar code for Onkeyup function to generate key pressed automatically.



//Second virtual keyboard:
const arabicInput = document.getElementById('myInput2');
const keyboardContainer = document.getElementById('keyboardContainer');
const phoneticMap = {// keyboards buttons
// Create keyboard keys
function createKeyboard() {
    for (const phonetic in phoneticMap) {
        const keyElement = document.createElement('div');
        keyElement.classList.add('key');
        keyElement.textContent = phoneticMap[phonetic];
        keyElement.dataset.phonetic = phonetic; // Store phonetic value
        keyboardContainer.appendChild(keyElement);
    }
}

// Handle key clicks
keyboardContainer.addEventListener('click', (event) => {
    const target = event.target;
    if (target.classList.contains('key')) {
        const phoneticKey = target.dataset.phonetic;
        if (phoneticKey === 'backspace') {
            arabicInput.value = arabicInput.value.slice(0, -1);
        } else if (phoneticKey === 'enter') {
            arabicInput.value += 'n';
        } else {
            arabicInput.value += phoneticMap[phoneticKey];
        }
        arabicInput.focus(); // Keep focus on the input field
    }
});

// Initialize the keyboard
createKeyboard();

// Here it is needed to add some code like ((document.getElementById("myInput").click();)) to make input box clicked automatically plus a similar code for Onkeyup function to generate key pressed automatically.

In React, why does useRef need .current but useState doesn’t?

I understand that Hooks like useState and useRef are valuable because they allow the user to store and update data that persists through re-renders. In short, useState is for data that should trigger a re-render when it’s updated, while useRef is for data that should not trigger a re-render when updated.

Ref:

// create
const count = useRef(0);
// write
count.current = 5;
// read
console.log(count.current);

State variable:

//create 
const [count, setCount] = useState(0);
// write
setCount(5);
// read
console.log(count);

Is there a design reason why the creators of React made it so reading the persistent value associated with a ref requires .current but reading the persistent value associated with a state variable doesn’t? I’m guessing there’s a good reason for it, but I have not been able to find the answer. Thank you for helping me to better understand.

Google Chat App with a Cloud Run Function – RenderActions and cardsV2 error

I am trying to build a Google Chat App that calls a Cloud Run function as the logic. I am assuming the GCP interfaces must have recently changed/updated because a lot of the guides and troubleshooting do not match the UI elements I am seeing in GCP.

I am getting the below two errors in my Log Explorer when I try to send a simple message to the Chat Bot.

Failed to parse JSON as RenderActions, DataActions or Card.
Failed to parse JSON as RenderActions. Failed with error: Cannot find field: cardsV2 in message google.apps.card.v1.RenderActions
Failed to parse JSON as DataActions. Failed with error: Cannot find field: cardsV2 in message google.apps.card.v1.DataActions
Failed to parse JSON as Card. Failed with error: Cannot find field: cardsV2 in message google.apps.card.v1.Card

and

Can't post a reply. The Chat app didn't respond or its response was invalid. If your Chat app is configured as an add-on, see "Build Google Chat interfaces" (https://developers.google.com/workspace/add-ons/chat/build) in the Google Workspace add-ons documentation. Otherwise, see "Receive and respond to Google Chat events" (https://developers.google.com/chat/api/guides/message-formats) in the Chat API documentation.

Below is my Cloud Function (Node.js).

/**
 * Google Chat Bot Echo function.
 *
 * This function is triggered by an HTTP request from Google Chat.
 * It processes the event payload and responds with a structured card message.
 *
 * @param {object} req The HTTP request object.
 * @param {object} res The HTTP response object.
 */
exports.chatBot = (req, res) => {
  // Check if the request method is POST. Google Chat sends POST requests.
  if (req.method !== 'POST') {
    return res.status(403).send('Forbidden');
  }

  const event = req.body;
  console.log('Received event:', JSON.stringify(event, null, 2));

  let responseMessage;

  // Handle different event types from Google Chat.
  switch (event.type) {
    case 'ADDED_TO_SPACE':
      // This event is triggered when the bot is added to a space or a DM.
      const spaceType = event.space.type;
      if (spaceType === 'DM') {
        responseMessage = `Hi ${event.user.displayName}! Thanks for starting a chat. I'll echo back anything you say.`;
      } else {
        responseMessage = `Thanks for adding me to ${event.space.displayName}! I'm ready to echo messages.`;
      }
      break;
    case 'MESSAGE':
      // This event is triggered when a user sends a message to the bot.
      // event.message.argumentText contains the text sent after the bot's @-mention.
      const userMessage = (event.message.argumentText || '').trim();
      if (userMessage) {
        responseMessage = `You said: "${userMessage}"`;
      } else {
        responseMessage = 'Hello! Please mention me and type a message.';
      }
      break;
    case 'REMOVED_FROM_SPACE':
      // This event is triggered when the bot is removed. No response is needed.
      console.log(`Bot removed from ${event.space.displayName}.`);
      return res.status(200).send();
    default:
      // For any other event type, send a default response.
      responseMessage = 'I received an event I don't know how to handle.';
      break;
  }
  
  // For a Google Workspace Add-on responding to a MESSAGE event,
  // the response must be a `renderActions` object.
  const reply = {
    "renderActions": {
      "action": {
        "navigations": [
          {
            "pushCard": {
              "header": {
                "title": "Echo Bot"
              },
              "sections": [
                {
                  "widgets": [
                    {
                      "textParagraph": {
                        "text": responseMessage
                      }
                    }
                  ]
                }
              ]
            }
          }
        ]
      }
    }
  };

  // Send the JSON response back to Google Chat.
  res.status(200).json(reply);
};

I am fairly new to GCP Google Chat API and Cloud Run Functions, so my apologies if this question seems a bit obvious. But I have been stuck for a while and cannot find a resolution anywhere. Any help would be much appreciate!

Alternative to getSVGForLocalExport in Highcharts 12.4.0?

In the past, we used getSVGForLocalExport() to retrieve svg for multiple charts so we could combine them into one output image (portion of code shown below). It appears getSVGForLocalExport() no longer exists in offline-exporting.js as of 12.3.0. Is there an alternative function that can be used for similar functionality? Thank you.

charts[i].getSVGForLocalExport(options, {}, function() {
        console.log('Failed to get SVG');
     }, function(svg) {
        addSVG(svg);
        // Export next only when this SVG is received
        return exportChart(i + 1);
     });

Three.js – DOF not working with point clouds (THREE.Points)

I’m trying to implement a Depth of Field (DOF) effect in a Three.js scene that includes a point cloud rendered using THREE.Points. I’ve based my implementation on these official examples:

These examples work well for standard 3D meshes like spheres or cubes. However, when I apply the DOF effect to a point cloud, the points remain uniformly blurry, regardless of their depth.

I’ve tried tweaking the focus, aperture, and maxblur values, but they don’t seem to have any visible effect on the point cloud.

const bokehPass = new BokehPass(
  scene,
  camera,
  {
    focus: 1.0,
    aperture: 0.025,
    maxblur: 0.01,
  }
);

I also tested the setup by adding a regular 3D sphere at the same position as the point cloud. The DOF effect works correctly on the sphere, but the point cloud remains unaffected.

How can I get DOF to work correctly?

Add an image to canvas in Javascript? [duplicate]

So I want to do a very simple thing, I think. I want to add a image to a 2d platform game I am making. The image itself is the level and after it is added I planned on adding invisble platforms on top of it to make the game playable. But how do you add the image in the first place?

Image: 8000 x 512 px Languages: Javascript, HTML, CSS

Tried EVERYTHING. I expect at least one method to work

Why I cannot send body with a fetch request when mode is no-cors?

Trying to make a cross-origing fetch request with the no-cors mode I found out it is not possible in this case to send any data to the server as a body:

const url = 'http://cross-origin-example.com/post';
const request = new Request(url, {
  method: 'POST',
  mode: 'no-cors',
  headers: {
    'Content-Type': 'text/plain',
  },
  body: 'boo',
});
fetch(url, request).then((response) => console.log(response));

In Chrome, such a request will not be sent at all throwing the following error:

Uncaught (in promise) TypeError: Failed to execute ‘fetch’ on
‘Window’: If request is made from ReadableStream, mode should
be”same-origin” or “cors”

Firefox make the request reach the server but with the body missing.

I know when using the no-cors mode the JS code gets an opaque response, which effectively conceals the result of fetching. However, on what basis the browsers do not allow attach body in this case? Is it standardized behavior (in fact, I failed to find such a restriction somewhere in the fetch spec) or just a browser extra limitation?

how to have a tick mark on a d3 x-axis for every year rather than every other

I want to have the x-axis show one tick per year, but I’m having trouble. I’m using the code provided on the d3 website. Can anyone advise?

<div id="container"></div>
<script type="module">

// Declare the chart dimensions and margins.
const width = 1140;
const height = 400;
const marginTop = 20;
const marginRight = 20;
const marginBottom = 30;
const marginLeft = 40;

// Declare the x (horizontal position) scale.
const x = d3.scaleUtc()
    .domain([new Date("2007-01-01"), new Date("2023-01-01")])
    .range([marginLeft, width - marginRight]); //shows one tick every other year
x.ticks(d3.utcYear.every(1)); //my code, but it doesn't work. x-axis still shows one tick every other year

// Declare the y (vertical position) scale.
const y = d3.scaleLinear()
    .domain([0, 100])
    .range([height - marginBottom, marginTop]);

// Create the SVG container.
const svg = d3.create("svg")
    .attr("width", width)
    .attr("height", height);

// Add the x-axis.
svg.append("g")
    .attr("transform", `translate(0,${height - marginBottom})`)
    .call(d3.axisBottom(x));


// Add the y-axis.
svg.append("g")
    .attr("transform", `translate(${marginLeft},0)`)
    .call(d3.axisLeft(y));

// Append the SVG element.
container.append(svg.node());

</script>

How to avoid label collision open layers?

I’m using OpenLayers in a vessel tracking map, and I have a custom label layer that renders vessel names.

The problem:
Even with declutter: true, many of the vessel labels overlap, and some disappear because they collide with others. This makes it hard to read vessel names when several vessels are close to each other.

What I’d like:
A “smarter” way of placing labels — e.g., automatically shifting a label to the NE, NW, SE, or SW of the vessel if it collides with another label, so that more of them remain visible. Ideally I want to try a few candidate positions per feature and pick one that doesn’t collide.

Below is a simplified version of my label-layer. I’m providing a few alternative styles but it’s not enough as when zoomed out alot of the labels disappear. Seems like all of the alternative styles need to be overlapping else the same label will appear multiple times.


  private createLabelLayer() {
    const layer = new VectorLayer({
      source: new VectorSource({
        overlaps: true,
      }),
      style: (feature) => {
        const vessel = this.vesselList.get(feature.get('vesselId'))

        const labelText = feature.get('text')
        style.getText()?.setText(labelText)

        const { dimensions } = vessel || {}
        let offY = 0
        let offX = 0
        if (dimensions) {
          style.getText()?.setOffsetY(offY)
          style.getText()?.setOffsetX(offX)
        }

        const styles = getLabelStyles(style, zIndex)

        return styles
      },
      declutter: true,
      zIndex: this.zIndexes.labels,
      maxResolution: this.thresholds.webglPoints,
    })
    layer.set('type', 'labelLayer')
    return layer
  }

const baselines: CanvasTextBaseline[] = ['middle', 'top', 'bottom']
const aligns: CanvasTextAlign[] = ['center', 'left', 'right']

const getLabelStyles = (baseStyle: Style, zIndex: number) => {
  const out: Style[] = [baseStyle]

  for (const bl of baselines) {
    for (const al of aligns) {
      const style = baseStyle.clone()

      const text = style.getText()

      text?.setTextBaseline(bl)
      text?.setTextAlign(al)
      text?.setOverflow(true)
      style.setZIndex(zIndex)

      out.push(style)
    }
  }
  return out
}

Is there a built-in way in OpenLayers to try alternative label positions, or is declutter: true the only out-of-the-box option?

Forge Viewer offline in Vue/Vite (iOS WebView) – call function across files without import/window/globalThis

We are building an offline Forge Viewer project using Vue + Vite, which will later be wrapped in an iOS app (Capacitor).

In offline mode, we need to serve model files and translations from a local cache. Normally, we’d use Cache Storage API and Service Worker, but those don’t work properly inside the iOS WebView environment.

So instead, we implemented a custom CacheService that can return cached model files (JSON, SVF, resources). Example:

// CacheService.js
class CacheService {
  async getModelFile(url) {
    // returns cached file content
  }
}

const cacheService = new CacheService();
export default cacheService;

In online mode, Forge Viewer fetches its resources normally.
In offline mode, we want to intercept Forge Viewer’s internal _rawGet calls and redirect them to cacheService.getModelFile(url) if available.

The problem:

  • Forge Viewer scripts are minified modules and run in a worker-like environment.

  • We cannot use:

    • import or importScripts (because it breaks inside Forge viewer worker logic)
    • window.cacheService (not defined in iOS WebView worker context)
    • globalThis.cacheService (also not reliable in this case)
    • Any global variable injection

So the question is:

How can we expose a function from one file and call it in another, in this environment, without relying on import, importScripts, window, or globalThis?

We basically need a way for Forge Viewer’s offline request code to call back into our own cacheService.getModelFile() implementation when a network request fails.

Any ideas on how to structure this or inject such a function in a Vite + Vue + Forge Viewer offline setup?

A way to expose a function (singleton) globally so that Forge Viewer’s internal request code can call it, without using import, window, globalThis, or service workers.