How to wait until element is visible for limited time?

I am waiting for a notification into portal after creating a service. Notification is not always visible on top and time is not fixed for it (I mean it takes max 10 seconds to show. If not visible within a 10 seconds will not appear on screen).

Now my test case is:
After creating a service, I want to wait until notification visible on the screen but want to bound it in a time. I can wait till 10 seconds. If notification visible within a 10 seconds, verify the text and if not visible in a time, reload the page.

I tried below one, but it is not working as expected:

export function verifyNotificationOfServiceCreation($text) {

    cy.get('body').then(($body) => {
        const $el = $body.find(getNotificationOnTop()); // Locate the element within the DOM
        if ($el.length && $el.is(':visible')) {
            //Verify notification text
            cy.wrap($el).should('have.text', $text);
            //Verify secondary text
            cy.contains('Refresh to see changes on page').should('be.visible')
            cy.contains('REFRESH', {matchCase: true}).should('be.visible').click()
            expect($el.text().trim()).to.equal('Expected Text');; // Element is found, visible, and condition met
        }
        return !$el.length; // Return true if element doesn't exist to exit wait
    })

}

It gives an error message ‘cy.then() failed because you are mixing up async and sync code.’

How can I set formatters for more than one column in React-Google-Charts?

Trying to use React Google Charts, I am facing a problem when I want to format several columns. In all the examples I found on the web, only one column is formatted through one of these two methods:

Method 1:

<Chart
            chartType="Table"
            width="700px"
            height="50%"
            data={data2}
            options={options}
            numberFormat={
                {
                    column: 6,
                    options: {
                        suffix: " €",
                        negativeColor: "red",
                        negativeParens: true,                
                    } 
                }
            }
        />`

Method 2:

 const formatters = [
        {
            type: "NumberFormat",
            column: 4,
            options: {
                pattern: "#",
            }
        }]
  <Chart
      chartType="Table"
      width="700px"
      height="50%"
      data={data2}
      options={options}
      formatters={formatters}
  />

Method 1 and Method 2 work fine but if I want to format columns 4 and 6, by extending the formatting array in any of the methods, only the first column will be formatted.

For example, I tried Method 2 with:

const formatters = [
        {
            type: "NumberFormat",
            column: 4,
            options: {
                pattern: "#Kg",
            }
        },
        {
            type: "NumberFormat",
            column: 6,
            options: {
                suffix: " €",
                negativeColor: "red",
                negativeParens: true,                
            } 
        }
    ]

and only column 4 was formatted.
If I permut the records then only column 6 will success.
Trying to play with brackets and/or parenthesis did not help.

How to move a legend to another line?

I’m using Chart.js and I’m trying to change the legend output. At the moment I have this code:

chart.options.plugins.legend.labels.generateLabels = (chart) => {
    const labels = [
        { text: `${dataset.label}`, fillStyle: dataset.borderColor },
        { text: `Last: ${lastValue}`, fillStyle: 'rgba(0, 0, 0, 0)' },
        { text: `Min: ${minValue}`, fillStyle: 'rgba(0, 0, 0, 0)' },
        { text: `Max: ${maxValue}`, fillStyle: 'rgba(0, 0, 0, 0)' },
        { text: `Avg: ${avgValue}`, fillStyle: 'rgba(0, 0, 0, 0)' }
    ];

    return labels;
};

I want to add additional lines (Last, Min, Max, Avg) under the main text (dataset.label value) so that they look like signatures.

I tried using n, but it doesn’t work.

How to correctly add additional lines under the main text of the legend in the Chart.js? Or is there a way to discard the legend and just add text under the graph?

Can Cloudflare detect that i read response body twice?

I’m building a Chrome extension. I need to intercept requests to a specific endpoint to get the response body and use the response in the extension (all ok, no malicious software)

To do that I overwrite window.fetch function with code:

const originalFetch = window.fetch;

window.fetch = async function (...args) {
  const response = await originalFetch(...args);
  const request = args[0];
  const url = request instanceof Request ? request.url : request instanceof URL ? request.href : request;

  if (url.includes('api/search')) {
    const data = await response.clone().json();

    if (data.myInfo) {
      window.dispatchEvent(
        new CustomEvent('OnMyInfoLoaded', {
          detail: {
            myInfo: data.myInfo,
          },
        }),
      );
    }
  }

  return response;
};

This script is injected in manifest:

        {
            "matches": [
                "https://external-website.com/*/*"
            ],
            "js": [
                "dist/injectCustomFetch.bundle.js"
            ],
            "run_at": "document_start"
        }

In 99% cases requests to search works and I get the data, but sometimes I get 403 forbidden from server. The server uses cloudflare so I assume cloudflare somehow detects that fetch is patched? I can’t access server logs/cloudflare logs as I’m not the owner of the server

This error is hard to catch too as most of the time it works fine, with occasional 403 and I don’t see any pattern

How to use localStorage variable to render modal [closed]

Have a modal, the open condition is when !localStorage.getItem("hasSeenModal") === "true", when close the modal, the onClose will do localStorage.setItem("hasSeenModal", true)

The modal will show up when app first loaded, and there is a button, the button onClick is to run localStorage.setItem("hasSeenModal", false), however, the modal won’t show up again immediately, unless refresh the browser, how do I do to make the modal open immediately by using localStorage variable

Integrate PowerBI with React App : crypto_nonexistent error

I am trying to embed PowerBI report in a react app. I have followed this example from microsoft. The example is in Typescript but I am using Javascript

Here is my index.js file.

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import { BrowserRouter } from "react-router-dom";
import { AuthProvider } from "./context/AuthProvider";
import { CountryProvider } from "./context/CountryProvider";
import theme from "./theme";
import { ThemeProvider } from "@mui/material/styles";
import { Provider } from "react-redux";
import { store } from "./store/store";
import * as config from "./pages/powerbi/keys";
import { LogLevel, PublicClientApplication } from "@azure/msal-browser";
import { MsalProvider } from "@azure/msal-react";

// TRIED THIS TO FIX THE ISSUE
if (typeof window !== 'undefined' && !window.crypto) {
  window.crypto = window.msCrypto;
}

const msalInstance = new PublicClientApplication({
  auth: {
      clientId: config.clientId,
      authority: config.authorityUrl,
      redirectUri: "http://{SERVER_IP_ADDRESS}/FOLDER_NAME/"
  },
  cache: {
      cacheLocation: 'localStorage', 
      storeAuthStateInCookie: false,
  },
  system: {
    loggerOptions: {
      loggerCallback: (level, message, containsPii) => {
        console.log(`LEVEL: ${level} MESSAGE: ${message}`);
      },
      piiLoggingEnabled: false,
      logLevel: LogLevel.Verbose
    },
    cryptoOptions: {
      usePkce: false // TRIED THIS TO FIX THE ISSUE
    }
  }
});

console.log("CRYPTO: ", window.crypto);

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
   <div id="MainDiv">
      <Provider store={store}>
         <BrowserRouter basename="Reactjs_Demo/">
            <AuthProvider>
               <CountryProvider>
                  <ThemeProvider theme={theme}>
                     <MsalProvider instance={msalInstance}>
                     <App />
                     </MsalProvider>
                  </ThemeProvider>
               </CountryProvider>
            </AuthProvider>
         </BrowserRouter>
      </Provider>
   </div>
);

And this is the PowerBI component

import React, { useEffect, useRef, useState, useContext } from "react";
import { AuthenticationResult, InteractionType, EventType, AuthError } from "@azure/msal-browser";
import { MsalContext } from "@azure/msal-react";
import { service, factories, models } from "powerbi-client";
import * as config from "./keys";

const powerbi = new service.Service(factories.hpmFactory, factories.wpmpFactory, factories.routerFactory);

export default function PowerBiReport() {
    const [accessToken, setAccessToken] = useState("");
    const [embedUrl, setEmbedUrl] = useState("");
    const [error, setError] = useState([]);
    const reportRef = useRef(null);
    const context = useContext(MsalContext);

    const authenticate = () => {
        const msalInstance = context.instance;
        const msalAccounts = context.accounts;
        const msalInProgress = context.inProgress;
        const isAuthenticated = context.accounts.length > 0;

        if (error.length > 0) {
            return;
        }

        const eventCallback = msalInstance.addEventCallback((message) => {
            if (message.eventType === EventType.LOGIN_SUCCESS && !accessToken) {
                const payload = message.payload;
                const name = payload.account?.name ? payload.account?.name : "";
                setAccessToken(payload.accessToken);
                setUsername(name);
                tryRefreshUserPermissions();
            }
        });

        const loginRequest = { scopes: config.scopeBase, account: msalAccounts[0] };

        if (!isAuthenticated && msalInProgress === InteractionType.None) {
            msalInstance.loginRedirect(loginRequest);
        } else if (isAuthenticated && accessToken && !embedUrl) {
            getEmbedUrl();
            msalInstance.removeEventCallback(eventCallback);
        } else if (isAuthenticated && !accessToken && !embedUrl && msalInProgress === InteractionType.None) {
            setUsername(msalAccounts[0].name);
            msalInstance.acquireTokenSilent(loginRequest).then((response) => {
                setAccessToken(response.accessToken);
                getEmbedUrl();
            }).catch((error) => {
                if (error.errorCode === "consent_required" || error.errorCode === "interaction_required" || error.errorCode === "login_required") {
                    msalInstance.acquireTokenRedirect(loginRequest);
                } else if (error.errorCode === '429') {
                    setError(["Our Service Token Server (STS) is overloaded, please try again in sometime"]);
                } else {
                    setError(["There was some problem fetching the access token" + error.toString()]);
                }
            });
        }
    };

    const tryRefreshUserPermissions = () => {
        fetch(config.powerBiApiUrl + "v1.0/myorg/RefreshUserPermissions", {
            headers: { "Authorization": "Bearer " + accessToken },
            method: "POST"
        })
        .then(response => {
            if (response.ok) {
                console.log("User permissions refreshed successfully.");
            } else {
                if (response.status === 429) {
                    console.error("Permissions refresh will be available in up to an hour.");
                } else {
                    console.error(response);
                }
            }
        })
        .catch(error => {
            console.error("Failure in making API call." + error);
        });
    };

    const getEmbedUrl = () => {
        fetch(config.powerBiApiUrl + "v1.0/myorg/groups/" + config.wspaceId + "/reports/" + config.reportId, {
            headers: { "Authorization": "Bearer " + accessToken },
            method: "GET"
        })
        .then(response => {
            const errorMessage = ["Error occurred while fetching the embed URL of the report", "Request Id: " + response.headers.get("requestId")];
            response.json()
            .then(body => {
                if (response.ok) {
                    setEmbedUrl(body["embedUrl"]);
                } else {
                    errorMessage.push("Error " + response.status + ": " + body.error.code);
                    setError(errorMessage);
                }
            })
            .catch(() => {
                errorMessage.push("Error " + response.status + ": An error has occurred");
                setError(errorMessage);
            });
        })
        .catch(error => {
            setError([error]);
        });
    };

    const setUsername = (username) => {
        const welcome = document.getElementById("welcome");
        if (welcome !== null) welcome.innerText = "Welcome, " + username;
    };

    useEffect(() => {
        if (reportRef.current !== null) {
            const reportContainer = reportRef.current;
            if (error.length) {
                reportContainer.textContent = "";
                error.forEach(line => {
                    reportContainer.appendChild(document.createTextNode(line));
                    reportContainer.appendChild(document.createElement("br"));
                });
            } else if (accessToken !== "" && embedUrl !== "") {
                const embedConfiguration = {
                    type: "report",
                    tokenType: models.TokenType.Aad,
                    accessToken,
                    embedUrl,
                    id: config.reportId,
                };
                const report = powerbi.embed(reportContainer, embedConfiguration);
                report.off("loaded");
                report.on("loaded", () => {
                    console.log("Report load successful");
                });
                report.off("rendered");
                report.on("rendered", () => {
                    console.log("Report render successful");
                });
                report.off("error");
                report.on("error", (event) => {
                    const errorMsg = event.detail;
                    console.error(errorMsg);
                });
            }
        }
    }, [accessToken, embedUrl, error]);

    useEffect(() => {
        authenticate();
    }, []);

    useEffect(() => {
        return () => {
            if (reportRef.current) {
                powerbi.reset(reportRef.current);
            }
        };
    }, []);

    return (
        <div>
            <div id="welcome"></div>
            <div ref={reportRef}>
                Loading the report...
            </div>
        </div>
    );
};


I don’t get any error when I am running the project locally on port 3000. But when I deploy to the server I get following error

Uncaught BrowserAuthError: crypto_nonexistent: The crypto object or function is not available.

this project was created using CRA. How to solve this?

What is the easiest way to import most of the Tailwind css classes?

I am working on building a website builder that uses Tailwind css to style things, but I am running into the issue where I add a class to a component, but nothing changes with the style. Come to find out, this is because that style class wasn’t generated yet, because it wasn’t part of my project. I looked to see if there was a way to import all the classes, but I couldn’t find anything. The closest thing that I could find, was using the safelist option in the tailwind.config.js, but I am running into difficulties. First, I have to manually try to add the classes. Second, I am running into the issue where the localhost webpage won’t even load. Third, it takes forever for the page to load, every time I update the code.

Have any advice? Other people have built apps that use the Tailwind CSS library, so I know there is a way to do it.

Sticky button stickied left taking up whole width?

Hello I have a button that is stickied to the bottom left but taking up whole space for some reason. Commenting display: flex and flex-direction: column in .todo-list does not allow the plus button to stay stickied to the bottom of the container on the container resize

naughty button

Button:

<div className="todo-list">            
    <button className="add-task-button" onClick={handleShowInput}>
        <img src={addIcon} alt="Add Task" className="add-icon" />
    </button>
</div>

Style:

.todo-list {
    position: relative;
    width: 100%;
    height: 100%;
    overflow-y: scroll;
    display: flex;
    flex-direction: column;


    p {
        margin: 0 0 0 2.4em;
    }

    ul {
        flex-grow: 1;
    }

    .add-task-button {
        position: sticky;
        background: none;
        border: none;
        cursor: pointer;
        display: flex;
        height: auto;
        bottom: 1em;
        left: 1em;
        width: auto;

        .add-icon {
            width: 2.2em;
            
        }

        &:hover {
            transform: scale(1.1);
        }
    }
}

Please help as you are my only hope anymore

Cannot Decode Buffer To Print BLE ECSPOS With React Native

I use React Native to listen for thermal printing request via LAN IP, then I get the Buffer data. But I don’t know how to decode it into text to send to Bluetooth Xprinter. Has anyone ever dealt with this case?

I tried with buffer.toString(‘utf-8’); but got error same in image

buffer.toString(‘utf-8’) got this error

My code handle it

import TcpSocket from 'react-native-tcp-socket';
import RNXprinter from "react-native-esc-pos-xprinter";
import { Buffer } from 'buffer';

const server = TcpSocket.createServer((socket) => {
      // socket.setEncoding('utf8');
      let binaryData = Buffer.alloc(0);
      socket.on('data', async (chunk) => {
        binaryData = Buffer.concat([binaryData, Buffer.from(chunk)]);
      });

      socket.on('error', (error) => {
        console.error('Socket error:', error);
      });

      socket.on('close', () => {
        console.log('Connection closed');
        const msg = binaryData.toString('utf-8');
        console.log('Received closed data:', msg);
        RNXprinter.pushText(msg, 0);

        // Push Cut Paper
        RNXprinter.pushCutPaper();
      });
    });

    server.listen({ port: parseInt(port, 10), host: '0.0.0.0' }, () => {
      console.log(`Server running on ${deviceIp}:${port}`);
      setServerRunning(true);
      Alert.alert('Print Server', `Server started on ${deviceIp}:${port}`);
    });
});

How to play PCM audio stream directly from WebSocket in Next.js frontend without saving to a file?

I’ve integrated VAPI.AI to handle inbound and outbound calling, and everything is working fine. There’s an option to listen to any inbound or outbound call through a WebSocket URL, which provides a PCM stream. Here’s my current setup:

I’m receiving PCM audio data through a WebSocket and saving it to a file (audio.pcm) on the server. Afterward, I use FFmpeg to convert it to an MP3 file, which I can then play without any issues. Below is my current code for receiving and saving the audio data:

const WebSocket = require('ws');
const fs = require('fs');

let pcmBuffer = Buffer.alloc(0);

const ws = new WebSocket("wss://aws-us-west-2-production1-phone-call-websocket.vapi.ai/7420f27a-30fd-4f49-a995-5549ae7cc00d/transport");

ws.on('open', () => console.log('WebSocket connection established'));

ws.on('message', (data, isBinary) => {
  if (isBinary) {
    pcmBuffer = Buffer.concat([pcmBuffer, data]);
    console.log(`Received PCM data, buffer size: ${pcmBuffer.length}`);
  } else {
    console.log('Received message:', JSON.parse(data.toString()));
  }
});

ws.on('close', () => {
  if (pcmBuffer.length > 0) {
    fs.writeFileSync('audio.pcm', pcmBuffer);
    console.log('Audio data saved to audio.pcm');
  }
});

ws.on('error', (error) => console.error('WebSocket error:', error));

Now, my question is:

Is there a way to play the PCM audio directly in the Next.js frontend (client-side) by using a WebSocket listener, without saving it to a file first? I want to stream the audio directly to the client as it is received from the WebSocket.

I’ve tried different solutions, but they result in noisy audio that is not clear. The playback sounds like noise, not the intended voice.

I’ve considered converting PCM to MP3 on the server and sending it to the frontend, but I’d prefer a more direct approach that avoids saving and converting the file if possible.

Any suggestions or solutions would be greatly appreciated!

How to resolve “An export assignment cannot be used in a module with other exported elements.” in dompurify 3.0.5 in purify.cjs.d.ts

I have an angular project uses “node”: “14.17.3”. Not sure what changed but all of a sudden I have an issue with dompurify 3.0.5.

Error: export ‘sanitize’ (imported as ‘DOMPurify’) was not found in ‘dompurify’ (possible exports: default)

So what I did was

“allowSyntheticDefaultImports”: true in tsconfig.json

and

import it as >> import { * as DOMPurify } from ‘dompurify’;

and

added @types/dompurify: ^3.0.2 in package.json

But now I got this issue

dompurify/dist/purify.cjs.d.ts:401:1 – error TS2309: An export assignment cannot be used in a module with other exported elements. 401 export = _default;

So I’m forcing it to import it as

import { default as DOMPurify } from ‘dompurify/dist/purify.es.mjs’;

But not I got this error

Module not found: Error: Package path ./dist/purify.es.mjs is not exported from package ..node_modulesdompurify (see exports field in ..node_modulesdompurifypackage.json)

Any idea how to resolve it? thank you!

My Cloudflare Worker that proxy image is not working properly

I deployed this on Cloudflare Worker and I have assigned domain proxy.mydomain.tld to the worker.
then I open https://proxy.mydomain.tld on browser but I couldn’t see the logo.png instead I see the error message says:

Too many redirects. https://www.mydomain.tld/logo.png (repeating same url..) https://www.mydomain.tld/logo.png

so I open original domain of worker (ends with workers.dev) and it is worked and show me the logo.png.

here is my worker code:

try {
  // fetch to my website.
  const imageResponse = await fetch("https://www.mydomain.tld/logo.png", {
    method: 'GET',
    headers: {
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 (compatible; ImageProxy/1.0; +http://mydomain.tld/proxy.html)'
    }
  });
  // return image
  return new Response(await imageResponse.blob(), {
    status: 200,
    headers: { 'Content-Type': imageResponse.headers.get('Content-Type') }
  });;
} catch (err) {  
  return new Response(err, {
    status: 500,
  });
}

proxy.mydomian.tld is proxied via Cloudflare, while others (e.g. *.mydomain.tld, mydomain.tld, www.mydomain.tld) is DNS-only.

P.S: mydomain.tld and *.mydomain.tld‘s A Record are points to my vps for frontend.
The Frontend VPS only installed certbot + nginx + zerotier vpn and configured to all HTTP(S) requests sent to www.mydomain.tld will forwarded to my HomeServer’s 80 port.
My HomeServer only installed nginx + zerotier vpn and hosting my website.
For HTTP=>HTTPS redirect and non-www to www redirect is done by Frontend Nginx.
And I thought this creepy setup cause this error.

How to use Notifications Web API

There is a basic example that shows how Notifications Web API works.

The example works well in Windows and Linux with Firefox/Chrome web browsers.

However, the example doesn’t show any notifications in Android with Chrome/Brave web browsers.

I cannot find any information in Web API documentation of how to use Notifications in Android. As well, there is no any direct information that Notifications API doesn’t work in Android.

Does Android supports the Web API Notifications?

URL of the example https://ide.geeksforgeeks.org/online-html-editor?id=a4376932-8096-4af9-aacf-c23accdcd205

Code:

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>Notifications example</title>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />

        <!-- Bootstrap/JQuery. -->
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous" />
        <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
        <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
        <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-+sLIOodYLS7CIrQpBjl+C7nPvqq+FbNUBDunl/OZv93DB7Ln/533i8e/mZXLi/P+" crossorigin="anonymous"></script>
    </head>
    <body class="container mt-3">
        <h2 class="mt-5">Notifications example</h2>

        <p>This example use only JavaScript. No server side used.</p>

        <input type="button" id="subscribe" value="Subscribe" class="btn btn-success" /><br />

        <button onclick="notifyMe()" class="btn btn-info mt-3">Notify me!</button>

        <button onclick="notifyMeWith7SecDelay()" class="btn btn-info mt-3">Notify me with 7 sec delay!</button>

        <script>
            $("#subscribe").on("click", function () {
                let promise = Notification.requestPermission();
            });

            function notifyMe() {
                if (!("Notification" in window)) {
                    alert("This browser does not support desktop notification");
                } else if (Notification.permission === "granted") {
                    const notification = new Notification("Hi there!", {
                        body: "Is an example of a notification"
                    });
                } else if (Notification.permission !== "denied") {
                    Notification.requestPermission().then((permission) => {
                        if (permission === "granted") {
                            const notification = new Notification("Hi there!", {
                                body: "Is an example of a notification"
                            });
                        }
                    });
                }
            }

            function notifyMeWith7SecDelay() {
                setTimeout(notifyMe, 7000);
            }
        </script>
    </body>
</html>

Getting uncaught reference error after trying to import data from another javascript file [duplicate]

I am getting this error Uncaught ReferenceError: assignment to undeclared variable numpick when I try to run my Javascript code after a button click. Below is my html file

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <h1>The Element Object</h1>
    <h2>The addEventListener() Method</h2>
    
    <p>Execute a function when a user clicks on a button:</p>
    
    <button id="myBtn">Pick it</button>
    
    <p id="demo">   
</body>
<script type="module"src="index.js"></script>
</html>

This is the javascript code that selects a number after a button click

import { mydata } from "./mynum.js";

const element = document.getElementById("myBtn");
element.addEventListener("click", myFunction);

function myFunction() {
  numpick = "1";
  personsel = mydata[numpick];
  console.log(personsel);
}

After trying to import this java script file mynum.js

export const mydata={"1":"John","2":"Lisa","3":"Peter"};

How can I automate sharing Reddit posts to unlock an achievement using JavaScript?

I’m trying to write a JavaScript script to automate sharing posts on Reddit to unlock the “Sharing Pro” achievement (which requires sharing 100 posts). My script is intended to:

  1. Locate the Share button on a Reddit post.
  2. Click the Share button to open the popup.
  3. In the popup, click the “Copy Link” option.
  4. Move to the next post and repeat until 100 posts are shared.

Here’s the code I’ve written so far:

let sharedCount = 0;

function sharePost() {
    if (sharedCount >= 100) {
        console.log("Achievement unlocked: Shared 100 posts!");
        return;
    }

    // Try to find the share button on the current post
    let shareButton = document.querySelector('shreddit-post-share-button');

    if (shareButton) {
        shareButton.click(); // Open the share popup
        setTimeout(() => {
            let copyLinkButton = document.querySelector('div[aria-label="Copy link"]');
            if (copyLinkButton) {
                copyLinkButton.click(); // Click "Copy Link"
                sharedCount++;
                console.log(`Shared posts: ${sharedCount}`);
            } else {
                console.log("Copy link button not found!");
            }
            window.scrollBy(0, 500); // Scroll to the next post
            setTimeout(sharePost, 1000); // Repeat after 1 second
        }, 1000);
    } else {
        console.log("Share button not found! Scrolling down...");
        window.scrollBy(0, 500); // Scroll down to find more posts
        setTimeout(sharePost, 1000); // Repeat after 1 second
    }
}

sharePost();

The problem:
The script scrolls the page as expected but is unable to locate the Share button. It ends up scrolling indefinitely without performing any sharing actions.

Here’s the HTML structure of the Share button:

<shreddit-post-share-button appearance="secondary" ...></shreddit-post-share-button>

And the “Copy Link” button inside the popup:

<div tabindex="0" ...>Copy link</div>

What I tried:
I expected document.querySelector('shreddit-post-share-button') to find the Share button, but it doesn’t. I’ve tried using different selectors, adding delays, and ensuring the page has loaded, but nothing seems to work.

My Questions:

  1. Why is my script unable to locate the shreddit-post-share-button element? Could it be related to how Reddit dynamically loads content?
  2. How can I improve the script to reliably identify and interact with the Share button and Copy Link option?