Extracting tables through puppeeteer

I am working on my university project. I want to extract data from my university LMS; I cracked the login authentication, and now I want to extract HTML of my subjects attendance and sessional marks data through Puppeeteer.

Here are my LMS credentials so you can understand the HTML code:
Link: https://my.kfueit.edu.pk/
username: COSC241103046
password: Sarmad.09

After entering the ‘home page’, go to ‘View my current enrollment.’

On this page, you can see all course details and 2 buttons, “Attendance” and “Sessional Marks.”

I want to get the course details like the course code, course name, credit hours, and section, and after all of that, click on the attendance button; a popup will appear; get the html code inside that; close the popup; click on the sessional marks button; a popup will show; get all the html code inside that; close the popup. This process repeats for all courses.

I tried to map through all courses, but it gives the wrong response.

    if (targetFrame) {
      await targetFrame.click('.fa.fa-book');
      await targetFrame.waitForSelector('tbody');

      const data = await targetFrame.evaluate(async () => {
        const rows = Array.from(document.querySelectorAll('tbody tr')).slice(1);
        console.log('33333333',rows)
        return Promise.all(rows.map(async row => {
          const cells = row.querySelectorAll('td');
          const rowsData = {
            courseCode: cells[0]?.innerText.trim(),
            courseName: cells[1]?.innerText.trim(),
            creditHours: cells[2]?.innerText.trim(),
            sections: cells[3]?.innerText.trim(),
          };
      
          const buttons = cells[4]?.querySelectorAll('button');
          if (buttons) {
            buttons[0].click();
            await new Promise(resolve => setTimeout(resolve, 500));
            const attendancePopup = document.querySelector('#courseAttendaceModel');
            const secondTable = attendancePopup?.querySelectorAll('table')[1];
            
            if (secondTable) {
              const attendanceRows = Array.from(secondTable.querySelectorAll('tr')).slice(1);
              rowsData.attendance = attendanceRows.map(attendanceRow => {
                const attendanceTds = attendanceRow.querySelectorAll('td');
                return {
                  td2: attendanceTds[2]?.innerText.trim() || 'No data',
                  td3: attendanceTds[3]?.innerText.trim() || 'No data',
                  td5: attendanceTds[5]?.innerText.trim() || 'No data',
                };
              });
            } else {
              rowsData.attendance = 'No attendance data';
            }
      
            const closeButton = attendancePopup?.querySelector('.btn.btn-default');
            if (closeButton) {
              closeButton.click();
              await new Promise(resolve => setTimeout(resolve, 500)); // Adjust delay to ensure popup closes
            }
          }
          return rowsData;
        }
      ));
      });
      console.log('enrollmentData', JSON.stringify(data, null, 2));
    }

After that, I tried to get only one course detail first, but it gave empty string.

    const data = await targetFrame.evaluate(() => {
      const rows = document.querySelectorAll('tbody tr:nth-child(2) td');
    
      return {
        courseCode: rows[0]?.innerHTML.trim() || '', 
        courseName: rows[1]?.innerHTML.trim() || '',
        creditHours: rows[2]?.innerHTML.trim() || '',
        section: rows[3]?.innerHTML.trim() || '',
      };
    });

    console.log('data: ', data)

I don’t know where I am wrong, but my end goal is to get attendance and sessional marks data for all courses.

Kindly help me to solve this and feel free to ask any question for clarification.

React: Dynamic color change every second

I need to write a function that will return either the color I specify or black every second. Right now, the color is set statically((cellStyle.backgroundColor = mapping.color)), but I need to make it dynamic. Could you please suggest how to implement this?
Example code:

export const Row = ({args}) => {
  ...
  const mapValue = (args) => {
    ...
    valueMappings.forEach((mapping) => {
      if (mapping.type === 'compare') {
            cellStyle.backgroundColor = mapping.color;
            cellStyle.color = 'black';
        }
      }
    });
    ...
  };
  const renderTableCell = (arg) => {
    ...
    let value = mapValue(arg);
    ...
    return (
      <div>...</div>
    );
  };
  return (
    <div>...</div>
  );
};

Random failure of playwright test due to timeout, if execution is done via bitbucket pipeline

enter image description hereI am running my playwright test using docker image image: mcr.microsoft.com/playwright:v1.49.0-noble
on edge,chrome,safari & firefox browsers using bitbucket pipeline.
Some tests are randomly failing due to timeout sometimes on fiefox or chrome even though sufficient wait is available.Once n several attempt, all tests are green as well. Locally also it works fine.

Below is the code for waituntil function.

async waitUntil(func, timeout = 1000, pollingRate = 100) {
        return new Promise((resolve, reject) => {
            const timer = setTimeout(() => {
                clearInterval(interval);
                reject(new Error('WaitUntil timed out'));
            }, timeout);
            const interval = setInterval(() => {
                if (!func())
                    return;

                clearTimeout(timer);
                clearInterval(interval);
                resolve();
            }, pollingRate);
        });
    }

Can anyone suggest something how the test can be stabilized in this case?

I tried disabling parallel execution -> no success
Already introduced sufficient wait but still no help.

How to validate v-select using vee-validate?

I’m trying to validate a select field in Vue. Currently using Vuetify2 and Vee-validate 3. It works for text field but v-select is not getting validated.

 <ValidationProvider name="Sources" rules="sourcesValidator" v-slot="{ errors }">
                    <v-select
                      v-model="sources"
                      :items="sourcesList"
                      dense
                      outlined
                      label="Select Source"
                      :error-messages="errors"
                    ></v-select>
</ValidationProvider>

import { ValidationObserver, ValidationProvider, extend } from 'vee-validate';

async created() {
    this.customValidator()
}

private customValidator() {
extend('sourcesValidator', {
      message: 'Source should be something else',
      validate: () => {
        console.log('here:', this.previousSource);
        return this.previousSource === 'CORP';
      }
    });
}

I’m calling a customValidator to validate my sources where I’m checking whether the previous selected data (which is another v-select) is CORP and return true or false. In short, if the previous selected value is CORP, then the sources cannot be empty. It must have a value. I added a console log, but it’s not getting inside the validate function. I’m not sure what’s going on. Any help would be greatly appreciated.

NextJS Leaflet problem with zoom and position tracking

I’ve been working on my problem for a while but I can’t seem to solve it:

I am a beginner on NextJs, I am working on a project of an interactive map for a game, currently my map works correctly, I can put markers etc.. Now I want to be able to track the user’s zoom and position on the map in real time with “CameraPositionTracker” component.

I want to have access to the zoom and position values from the parent component (‘Map’), so I’ve created 2 State (zoomLevel and cameraPosition)

Map component :

'use client';

import 'leaflet/dist/leaflet.css'

import { useEffect, useState } from 'react';
import { MapContainer, TileLayer, useMap } from 'react-leaflet';
import L, { CRS } from 'leaflet';

import Mark from '@/components/map/Mark';

import CameraPositionTracker from '@/components/map/CameraPositionTracker';
import ViewBounds from '@/components/map/ViewBounds';

const mapMaxResolution = 1.00000000;
const mapMinZoom = 3;
const mapMaxZoom = 5;
const CustomCRS = {
  ...CRS.Simple,
  transformation: new L.Transformation(1, 0.00000000, -1, 0.00000000),
  scale: (zoom) => Math.pow(2, zoom) / (Math.pow(2, mapMaxZoom) * mapMaxResolution), // mapMaxZoom = 4, mapMaxResolution = 1.0
  zoom: (scale) => Math.log(scale * ((Math.pow(2, mapMaxZoom) * mapMaxResolution))) / Math.LN2,
}


const Map = ({ markers }) => {
  const [map, setMap] = useState(null);
  const mapExtent = [0.00000000, -7500.00000000, 7500.00000000, 0.00000000]; // xmin, ymin, xmax, ymax
  
  const [zoomLevel, setZoomLevel]  = useState(3)
  const [cameraPosition, setCameraPosition] = useState(null);

  useEffect(() => {    
    console.log("zoom : ",zoomLevel);
  }, [zoomLevel]);  

  return (
    <div className="">
      <MapContainer
        crs={CustomCRS}
        center={[0, 0]}
        minZoom={mapMinZoom}
        maxZoom={mapMaxZoom}
        zoomControl={false}
        style={{ height: '100vh', width: '100%', position: 'relative'}}
        // whenCreated={(map) => setMap(map)}
        // whenCreated={(map) => (mapRef.current = map)}
        attributionControl={false}
        // onZoomEnd={() => setZoomLevel()}
      >
        <TileLayer
          url="http://localhost:3000/images/tiles/{z}/{y}/{x}.png"
          tileSize={256}
          minZoom={mapMinZoom}
          maxZoom={mapMaxZoom}
          noWrap={true}
          tms={false}
          maxBounds={[
            [-7500, 0],
            [0, 7500],
          ]}
          maxBoundsViscosity={1.0}
          bounds={[
            {lat: 0, lng: 7500}, // Bottom-left (ymin, xmin)
            {lat: -7500, lng: 0}, // Top-right (ymax, xmax)
          ]}
        />

        <CameraPositionTracker setZoomLevel={setZoomLevel} setCameraPosition={setCameraPosition}/>
        <ViewBounds mapExtent={mapExtent} />

        {markers.filter((marker) => marker.isDisplayed).map(marker => (
          <Mark key={marker.id} position={[marker.coordinates.lat,marker.coordinates.long]} data={marker}/>
        ))}
      </MapContainer>
    </div>
  );
}

export default Map;

CameraPositionTracker component :

const CameraPositionTracker = ({ setZoomLevel, setCameraPosition }) => {
    // const [zoomLevel, setZoomLevel] = useState(3); // initial zoom level provided for MapContainer
    
    const map = useMap();

    const onZoom = () => {
        const currentZoomLevel = map.getZoom();
        setZoomLevel(currentZoomLevel);
    }

    const onMove = () => {
        const currentCameraPosition = map.getCenter(); 
        setCameraPosition({ lat: currentCameraPosition.lat, lng: currentCameraPosition.lng });
    }

    useEffect(() => {
               
        map.on("moveend", onMove);
        map.on("zoomend", onZoom);

        return () => {
            map.off('zoomend', onZoom);
            map.off("moveend", onMove);
        }
    }, []);
    
    return null
}

With this code I can track the zoom when I zoom in on the map, so far so good.

The code below only works when I declare the state directly in the ‘CameraPositionTracker’ component, but when I use the state of the parent component, the map zoom is updated each time to the initial state of my zoom. So in the end my ‘zoomLevel’ state remains the same and never changes, and visually it creates a zoom-in then zoom-out effect.

Finally I have the impression that my state is synchronised with the map but in a completely buggy way, even though I don’t want it to be synchronised with it. In the attributes of my map I don’t have ‘zoom={zoomLevel}’ which would normally synchronise.

When I do the same thing in the component but for the position, it creates an infinite loop and makes everything crash.

I hope I’ve made my problem as clear as possible, and thank you in advance for any help you can give me.

Using the event object in an anonymous handler

I have to handle an event by two actions, each one being done by a named function. I’d call them in an anonymous listener like this (is it correct?):

element.click( function() {
     action1();
     action2();
});

Now, in reality action1 needs the event object as argument, so I tried this syntax:

element.click( function(ev) {
     action1(ev);
     action2();
});

But that does not work. Is there a problem here? (There may be a bug elsewhere in my code…)

ERROR: pip’s dependency resolver does not currently take

ERROR: pip’s dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.
tensorflow 2.14.0 requires keras<2.15,>=2.14.0, but you have keras 3.7.0 which is incompatible.
tf-keras 2.17.0 requires tensorflow<2.18,>=2.17, but you have tensorflow 2.14.0 which is incompatible.

SOLVE text

Why does this code output order is not as expected by Promise-setTimeout-regular code chain in React

I’m confused by the output of the below code, simply it’s like this;

setTimeout(() => {
    console.log("Timeot inner code");
  }, 500);

  promiseInner();

  console.log("Regular inner");

  useEffect(() => {
    setTimeout(() => {
      console.log("Timeout useEffect");
    }, 500);

    promiseUseEffect();

    console.log("Regular useEffect");
  }, []);

  async function promiseInner() {
    console.log("Promise inner");
  }
  async function promiseUseEffect() {
    console.log("Promise useEffect ");
  }

So one timeout first, then Promise, then a regular code followed by a useEffect. Aware that there is no await before Promises.

The output of above code is;

enter image description here

Which seems kinda weird, I’ve expected the below output;

  • Regular inner
  • Promise inner
  • Regular useEffect
  • Promise useEffect
  • Timeot inner code
  • Timeout useEffect

Since Promise is a microtask but there is no await, I thought it will be executed after the regular code, but here it is executed before the regular code.

So I’m left with this question and completely have no idea what’s going on.

  • Why the Promises are executed before the regular codes since there
    is no await?

After update from Expo SDK 51 to Expo SDK 52, barcode scanner has removed. I try to implement barcode scanner with expo-camera but having error

When I try to implement expo-camera for barcode scanning, i get the error that below. How should I solve the problem? Can anyone help me? My expo sdk version and expo-camera versions are “expo-camera”: “~16.0.7”, “expo”: “^52.0.0”,

”’

import React, { useState, useEffect } from 'react';
import { Text, View, StyleSheet, Alert, Button } from 'react-native';
import { Camera } from 'expo-camera';
import { getFirestore, doc, getDoc, updateDoc } from 'firebase/firestore';
import { getCurrentUser } from './backend';

export default function QRCodeScanner({ navigation }) {
    const [hasPermission, setHasPermission] = useState(false);
    const [scanned, setScanned] = useState(false);
    const [currentUser, setCurrentUser] = useState(null);

    useEffect(() => {
        const getPermissions = async () => {
            const { status } = await Camera.requestCameraPermissionsAsync();
            setHasPermission(status === 'granted');
        };

        const fetchUser = async () => {
            const user = await getCurrentUser();
            if (user) {
                setCurrentUser(user);
            } else {
                navigation.navigate('Login');
            }
        };

        getPermissions();
        fetchUser();
    }, [navigation]);

    const handleBarCodeScanned = async ({ data }) => {
        if (scanned) return;
        setScanned(true);

        try {
            const url = new URL(data);
            const tableId = url.pathname.split('/').pop();
            const db = getFirestore();
            const tableDocRef = doc(db, 'tables', tableId);
            const tableDoc = await getDoc(tableDocRef);

            if (!tableDoc.exists()) {
                Alert.alert('Error', 'Table does not exist');
                setScanned(false);
                return;
            }

            const tableData = tableDoc.data();
            const userId = currentUser?.id;
            const userName = `${currentUser?.name || ''} ${currentUser?.surname || ''}`;

            if (!userId) {
                Alert.alert('Error', 'Current user is not defined');
                setScanned(false);
                return;
            }

            if (!tableData.player1) {
                await updateDoc(tableDocRef, { player1: userId, player1Name: userName });
                navigation.navigate('PlayerOptions', { gameId: tableDoc.id, playerNumber: 'player1' });
            } else if (!tableData.player2) {
                await updateDoc(tableDocRef, { player2: userId, player2Name: userName });
                navigation.navigate('Scoreboard', { gameId: tableDoc.id, playerNumber: 'player2', player1Name: tableData.player1Name, player1Ball: tableData.player1Ball, player2Name: userName });
            } else {
                Alert.alert('Error', 'Table is already full');
            }
        } catch (error) {
            console.error('Error connecting as player:', error);
            Alert.alert('Error', 'Permission denied. Please check your Firebase rules.');
        } finally {
            setScanned(false);
        }
    };

    if (!hasPermission) {
        return <Text>No access to camera</Text>;
    }

    return (
        <View style={styles.container}>
            <Camera
                style={StyleSheet.absoluteFill}
                onBarCodeScanned={scanned ? undefined : handleBarCodeScanned}
            />
            {scanned && <Button title="Tap to Scan Again" onPress={() => setScanned(false)} />}
        </View>
    );
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
    },
});

”’

***(NOBRIDGE) ERROR Warning: React.jsx: type is invalid — expected a string (for built-in components) or a class/function (for composite components) but got: object.

Check your code at QRCodeScanScreen.js:81.
in QRCodeScanner (created by SceneView)
in StaticContainer
in EnsureSingleNavigator (created by SceneView)
in SceneView (created by SceneView)
in RCTView (created by View)
in View (created by DebugContainer)
in DebugContainer (created by MaybeNestedStack)
in MaybeNestedStack (created by SceneView)
in RCTView (created by View)
in View (created by SceneView)
in RNSScreen (created by Animated(Anonymous))
in Animated(Anonymous)
in Suspender (created by Freeze)
in Suspense (created by Freeze)
in Freeze (created by DelayedFreeze)
in DelayedFreeze
in InnerScreen (created by Screen)
in Screen (created by SceneView)
in SceneView (created by NativeStackViewInner)
in Suspender (created by Freeze)
in Suspense (created by Freeze)
in Freeze (created by DelayedFreeze)
in DelayedFreeze (created by ScreenStack)
in RNSScreenStack (created by ScreenStack)
in Unknown (created by ScreenStack)
in ScreenStack (created by NativeStackViewInner)
in NativeStackViewInner (created by NativeStackView)
in RNCSafeAreaProvider (created by SafeAreaProvider)
in SafeAreaProvider (created by SafeAreaProviderCompat)
in SafeAreaProviderCompat (created by NativeStackView)
in NativeStackView (created by NativeStackNavigator)
in PreventRemoveProvider (created by NavigationContent)
in NavigationContent
in Unknown (created by NativeStackNavigator)
in NativeStackNavigator (created by App)
in EnsureSingleNavigator
in BaseNavigationContainer
in ThemeProvider
in NavigationContainerInner (created by App)
in App (created by withDevTools(App))
in withDevTools(App)
in RCTView (created by View)
in View (created by AppContainer)
in RCTView (created by View)
in View (created by AppContainer)
in AppContainer
in main(RootComponent)
(NOBRIDGE) ERROR Warning: React.jsx: type is invalid — expected a string (for built-in components) or a class/function (for composite components) but got: object.

Check your code at QRCodeScanScreen.js:81.
in QRCodeScanner (created by SceneView)
in StaticContainer
in EnsureSingleNavigator (created by SceneView)
in SceneView (created by SceneView)
in RCTView (created by View)
in View (created by DebugContainer)
in DebugContainer (created by MaybeNestedStack)
in MaybeNestedStack (created by SceneView)
in RCTView (created by View)
in View (created by SceneView)
in RNSScreen (created by Animated(Anonymous))
in Animated(Anonymous)
in Suspender (created by Freeze)
in Suspense (created by Freeze)
in Freeze (created by DelayedFreeze)
in DelayedFreeze
in InnerScreen (created by Screen)
in Screen (created by SceneView)
in SceneView (created by NativeStackViewInner)
in Suspender (created by Freeze)
in Suspense (created by Freeze)
in Freeze (created by DelayedFreeze)
in DelayedFreeze (created by ScreenStack)
in RNSScreenStack (created by ScreenStack)
in Unknown (created by ScreenStack)
in ScreenStack (created by NativeStackViewInner)
in NativeStackViewInner (created by NativeStackView)
in RNCSafeAreaProvider (created by SafeAreaProvider)
in SafeAreaProvider (created by SafeAreaProviderCompat)
in SafeAreaProviderCompat (created by NativeStackView)
in NativeStackView (created by NativeStackNavigator)
in PreventRemoveProvider (created by NavigationContent)
in NavigationContent
in Unknown (created by NativeStackNavigator)
in NativeStackNavigator (created by App)
in EnsureSingleNavigator
in BaseNavigationContainer
in ThemeProvider
in NavigationContainerInner (created by App)
in App (created by withDevTools(App))
in withDevTools(App)
in RCTView (created by View)
in View (created by AppContainer)
in RCTView (created by View)
in View (created by AppContainer)
in AppContainer
in main(RootComponent)
(NOBRIDGE) ERROR Warning: Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.

Check the render method of QRCodeScanner.
This error is located at:
in RCTView (created by View)
in View (created by QRCodeScanner)
in QRCodeScanner (created by SceneView)
in StaticContainer
in EnsureSingleNavigator (created by SceneView)
in SceneView (created by SceneView)
in RCTView (created by View)
in View (created by DebugContainer)
in DebugContainer (created by MaybeNestedStack)
in MaybeNestedStack (created by SceneView)
in RCTView (created by View)
in View (created by SceneView)
in RNSScreen (created by Animated(Anonymous))
in Animated(Anonymous)
in Suspender (created by Freeze)
in Suspense (created by Freeze)
in Freeze (created by DelayedFreeze)
in DelayedFreeze
in InnerScreen (created by Screen)
in Screen (created by SceneView)
in SceneView (created by NativeStackViewInner)
in Suspender (created by Freeze)
in Suspense (created by Freeze)
in Freeze (created by DelayedFreeze)
in DelayedFreeze (created by ScreenStack)
in RNSScreenStack (created by ScreenStack)
in Unknown (created by ScreenStack)
in ScreenStack (created by NativeStackViewInner)
in NativeStackViewInner (created by NativeStackView)
in RNCSafeAreaProvider (created by SafeAreaProvider)
in SafeAreaProvider (created by SafeAreaProviderCompat)
in SafeAreaProviderCompat (created by NativeStackView)
in NativeStackView (created by NativeStackNavigator)
in PreventRemoveProvider (created by NavigationContent)
in NavigationContent
in Unknown (created by NativeStackNavigator)
in NativeStackNavigator (created by App)
in EnsureSingleNavigator
in BaseNavigationContainer
in ThemeProvider
in NavigationContainerInner (created by App)
in App (created by withDevTools(App))
in withDevTools(App)
in RCTView (created by View)
in View (created by AppContainer)
in RCTView (created by View)
in View (created by AppContainer)
in AppContainer
in main(RootComponent)
(NOBRIDGE) ERROR Warning: Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
Check the render method of QRCodeScanner.
This error is located at:
in RCTView (created by View)
in View (created by QRCodeScanner)
in QRCodeScanner (created by SceneView)
in StaticContainer
in EnsureSingleNavigator (created by SceneView)
in SceneView (created by SceneView)
in RCTView (created by View)
in View (created by DebugContainer)
in DebugContainer (created by MaybeNestedStack)
in MaybeNestedStack (created by SceneView)
in RCTView (created by View)
in View (created by SceneView)
in RNSScreen (created by Animated(Anonymous))
in Animated(Anonymous)
in Suspender (created by Freeze)
in Suspense (created by Freeze)
in Freeze (created by DelayedFreeze)
in DelayedFreeze
in InnerScreen (created by Screen)
in Screen (created by SceneView)
in SceneView (created by NativeStackViewInner)
in Suspender (created by Freeze)
in Suspense (created by Freeze)
in Freeze (created by DelayedFreeze)
in DelayedFreeze (created by ScreenStack)
in RNSScreenStack (created by ScreenStack)
in Unknown (created by ScreenStack)
in ScreenStack (created by NativeStackViewInner)
in NativeStackViewInner (created by NativeStackView)
in RNCSafeAreaProvider (created by SafeAreaProvider)
in SafeAreaProvider (created by SafeAreaProviderCompat)
in SafeAreaProviderCompat (created by NativeStackView)
in NativeStackView (created by NativeStackNavigator)
in PreventRemoveProvider (created by NavigationContent)
in NavigationContent
in Unknown (created by NativeStackNavigator)
in NativeStackNavigator (created by App)
in EnsureSingleNavigator
in BaseNavigationContainer
in ThemeProvider
in NavigationContainerInner (created by App)
in App (created by withDevTools(App))
in withDevTools(App)
in RCTView (created by View)
in View (created by AppContainer)
in RCTView (created by View)
in View (created by AppContainer)
in AppContainer
in main(RootComponent)***

Verify a text input’s pattern does not conflict with the maxlength attribute

I am creating a dynamic form in which the user can define the inputs and its attributes. Two options available are to add a regex pattern and a maxlength attribute that the end user of the form must comply with to submit.

If the user defines an input like this

<input type="text" required maxlength="3">

What is the best way of verifying whether adding regex like pattern=".{5,10}" will make a valid input impossible?

This check will be used to ensure the user is not allowed to produce a form with these kinds of impossible inputs so any alternative solutions would also be appreciated.

I understand there may be some kind of regex I can check the pattern against? The actual values of the pattern and maxlength are determined through vue variables so using javascript to solve this problem is an option.

Puppeteer – pass variable to selector

new to puppeteer and having trouble understanding how I can pass a variable to the browser inside the querySelector

I’ve got something to that goes and queries number of active users and returns the value

    const usedLicenses = await page.evaluate(() => {
            return document.querySelector('#root > div > main > div > div:nth-child(2) > div > div:nth-child(3) > strong').textContent;
  });

If usedLicenses is not 0, I then wish to loop from 1 to whatever the value is to return some further info using this selector

Ignoring the loop requirement for a minute, it seems like I need something like this but how do I use the variable properly inside the selector?

 const activeUsers = await page.evaluate(({usedLicenses}) => {
    return document.querySelector('#root > div > main > div > div:nth-child(3) > ul > li:nth-child(usedLicenses) > div.title > strong').textContent;
   },{usedLicenses});

Thanks

How to fix “xxx is not defined” error in JavaScript?

I’m trying to run a JavaScript function, but I’m getting the error:

Uncaught ReferenceError: xxx is not defined

Here’s a snippet of my code:
function myFunction() { console.log(xxx); } myFunction();

I expected it to log a value, but instead, it throws the error.

What causes this error?
How can I define or correctly use xxx in my script?
I’m using [browser/Node.js], and I’ve tried searching for similar issues but couldn’t figure out a solution. Any help would be appreciated!

insertAdjacentElement only renders on page refresh

I’m developing a chrome extension. Problem arises when I attempt to insertAdjacentElement. I can see that the css style is added to the page head but not the element itself until I refresh the page. I’ve tried checking the document load completion state and adding setTimeouts. Not sure how to go about it.


export const config: PlasmoCSConfig = {
  matches: ["https://www.linkedin.com/*"],
  all_frames: true
}

let lastUrl = location.href
new MutationObserver(() => {
  const url = location.href
  if (url !== lastUrl) {
    lastUrl = url
    onUrlChange()
  }
}).observe(document, { subtree: true, childList: true })

function onUrlChange() {
  if (document.readyState === "complete") {
    console.log("URL changed!", location.href)
    GhostOverview()
  }
}

function AddContainer() {
  const style_element = document.createElement("style")
  style_element.innerHTML = `
      .sample-container {
        width: 500px;
        border: 1px solid rgba(0, 0, 0, .5);  
        border-radius: 5px;
        margin-top: 30px;
        padding-top: 10px;
        padding-left: 10px;
        padding-bottom: 10px;
      } 
      .title-header {
        color: black;
        font-size: 18px; 
        font-weight: bold;
      }
    `
  document.head.appendChild(style_element)

  const document_div = document.getElementsByClassName("t-14")[0]
  if (document_div) {
    const testDiv = document.createElement("div")
    testDiv.className = "ghost-container"
    testDiv.innerHTML = '<h2 class="ghost-header">Header</h2>'
    document_div.insertAdjacentElement("afterend", testDiv)
    
  }
}


export default function GhostOverview() {
  if (window.location.toString().includes("linkedin.com/jobs/search/")) {

    
    AddContainer()
...

Jest test kept failing so I decided to debug by using console.log(lowerCaseRegex.test(string)); but then the test passed because of that console.log?

I have the following custom hook which has a function that takes a string which might contain an interpolation which requires me to lower case the string inside of it, like this:

Hello, I am {{#lowerCase}}Lower Case{{/lowerCase}}

should become

Hello, I am lower case

Now this works fine, however, as I started testing the hook, the results were a bit weird. My hook looks like this:

import { useCallback, useMemo } from 'react';

const useIntepolatedMessage = () => {
    const lowerCaseRegex = useMemo(() => /{{#lowerCase}}(.*?){{/lowerCase}}/g, []);

    const lowerCaseInterpolation = useCallback(
        (inputString: string) => {
            const result = inputString.replace(lowerCaseRegex, (match, group) => group.toLowerCase());

            return result;
        },
        [lowerCaseRegex]
    );

    const interpolatedMessage = useCallback(
        (string: string) => {
            if (!lowerCaseRegex.test(string)) return string;

            if (lowerCaseRegex.test(string)) {
                string = lowerCaseInterpolation(string);
            }

            return string;
        },
        [activityContentRegex, controller?.steps, lowerCaseInterpolation, lowerCaseRegex, userActivityContent]
    );

    return { interpolatedMessage };
};

export default useIntepolatedMessage;

The weird issue is that my test is failing until I console.log(lowerCaseRegex.test(string)); right before the:

            if (lowerCaseRegex.test(string)) {
                string = lowerCaseInterpolation(string);
            }

If that console.log(lowerCaseRegex.test(string)); is present, the string gets interpolated even though console.log(lowerCaseRegex.test(string)); evaluates to false.

Is there something wrong with my code?