Unit Test Svelte Component { #if }

Reproduction Steps

Setup

Bash mkdir example && cd example && mkdir src && touch jest.config.js && pnpm init && pnpm i @jest/globals @testing-library/svelte jest jest-environment-jsdom svelte svelte-jester -D && cd src && touch Example.test.js && touch Example.svelte && cd ..

Add to package.json

{
  "type": "module",
  "scripts": {
    "test": "NODE_OPTIONS=--experimental-vm-modules pnpm jest"
  }
}

jest.config.js

/** @type { import('jest').Config } */
const config = { // https://jestjs.io/docs/configuration
  clearMocks: true, // Automatically clear mock calls, instances, contexts and results before every test
  collectCoverage: true, // Indicates whether the coverage information should be collected while executing the test
  coverageDirectory: 'coverage', // The directory where Jest should output its coverage files
  coverageProvider: 'v8', // Indicates which provider should be used to instrument code for coverage
  injectGlobals: false, // Insert Jest's globals (expect, test, describe, beforeEach etc.) into the global environment. If you set this to false, you should import from @jest/globals
  testEnvironment: 'jest-environment-jsdom', // The test environment that will be used for testing. The default environment in Jest is a Node.js environment. If you are building a web app, you can use a browser-like environment via 'jest-environment-jsdom'
  moduleFileExtensions: ['js', 'svelte'], // An array of file extensions your modules use
  extensionsToTreatAsEsm: ['.svelte'], // If you have files that are not `.js` and `.cjs` that should run with native ESM, you need to specify their file extension here
  transform: { '^.+\.svelte$': 'svelte-jester' }, // https://www.npmjs.com/package/svelte-jester
}

export default config

Example.svelte

<script>
  let value

  function setValue (e) {
    value = e.target.value
  }
</script>


<textarea on:input={ setValue }></textarea>
{ #if value }
  { value }
{ /if }

Example.test.js

import Example from './Example.svelte'
import { describe, test, expect } from '@jest/globals'
import { render, fireEvent, screen } from '@testing-library/svelte'


describe('Example.svelte', () => {
  test('works', async () => {
    expect(document.body.innerHTML).toEqual('')
    const { getByText, container } = render(Example)
    expect(container.innerHTML).toEqual('<div><textarea></textarea> </div>')

    const expected = 'hello world'
    const textarea = container.querySelector('textarea')
    textarea.value = expected
    await fireEvent(textarea, new InputEvent('input'))

    expect(container.innerHTML).toEqual('<div><textarea></textarea> hello world</div>')
    expect(getByText(expected)).toBeTruthy()
    expect(screen.getByText(expected)).toBeTruthy()
  })
})

Test Results

  • All the tests pass
  • Uncovered Line #s is 11 which is this line in Example.svelte => { #if value }
 PASS  src/Example.test.js
  Example.svelte
    ✓ works (26 ms)

----------------|---------|----------|---------|---------|-------------------
File            | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------------|---------|----------|---------|---------|-------------------
All files       |     100 |        0 |     100 |     100 |                   
 Example.svelte |     100 |        0 |     100 |     100 | 11                
----------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.113 s

How may I test line 11 please?!

ReactJs : unable to reset input field to “”

I’m having application with React v 0.13.6 (Old version).
I’m unable to update my input field to “” after fetching updated value from DB.

Scenario: I’m updating the input fields by clicking on button “Pull”. Functionality of this button is to fetch the data from a separate DB and then save the data in my DB to update the input fields value.

Child Component

<div>
<div style={this.props.Styles.divItem} data-id={this.props.AddressArray["flat_no"]}>
<div style={this.props.Styles.label}>Flat no.</div>
<Input Type="text"  
Value={this._getValue(this.props.AddressArray["flat_no"])}  
ValueChanged={value => this._DataItemValueChanged(value, this.props.AddressArray["flat_no"])}/>
</div>
</div>

Method to fetch input field value

    _getValue(itemId) {
        
        var currentValue = this.props.Details[this.props.Section][itemId];

        if(currentValue === undefined) {
            return "";
        }

        return currentValue.Value;
    },

There is a separate method to fetch data from DB and populate props, which is doing its job.
But the input field is not getting updated if its blank i.e. “”. If it has any value like 9, it will update.
Also it will reset as blank after pulling data only if I refresh the page, else it will sustain its old value.

Can anyone please guide me on how to do this? Thanks in advance.

Understanding Javascript ternary operator syntax and reduce syntax

I’m using javascript and trying to combine reduce and the ternary if/else statement. I am getting an extremely unexpected result and I cannot figure out why. It almost seems like a bug in branch prediction or something for my system. Below is a snippet with a test case.

testInput = [{valid:true,id:647},{valid:false,id:114}]

function sumValid(total, validIdObj){
    var intermediary;
    if(validIdObj.valid){
        intermediary = validIdObj.id;
    }
    else{
        intermediary = 0;
    }
    return total + intermediary;
}

function sumInvalid(total, validIdObj){
    return total + (validIdObj.valid)? validIdObj.id:0;
}

function sumSwapped(total, validIdObj){
    return total + (validIdObj.valid)? 0:validIdObj.id;
}

answer = 0
answer += testInput.reduce(sumValid, 0);
console.log(answer)

answer = 0
answer += testInput.reduce(sumInvalid, 0);
console.log(answer)

answer = 0
answer += testInput.reduce(sumSwapped, 0);
console.log(answer)

The expected output in the console is (unless I’m just being dumb?):

647
647
114

The actual output in the console is:

647
114
114

I don’t see how the sumInvalid and sumSwapped functions could be returning the same value. It looks like they should always be giving different answers (except with inputs including an “id” value of 0).

Since this sorta seems like a bug I’ll include that I’m using ungoogled-chromium Version 119.0.6045.199.

I’ve tried stepping through the code in the debugger, and it looks like “total” in the sumInvalid function after the first step/iteration of reduce is 647, and the total after the second step of reduce is somehow 114. Given the numbers are 647 and 114 and there isn’t a mathematical way to move from 647 to 114 by adding 114 this seems like it may be a caching/branch prediction bug.

Is there a better way to look at whats going on or that allows you to step through the individual sections of a ternary operator?

How to update javascript file with function url from Terraform?

I currently have a Terraform file that is used to set up a website with s3 and CloudFront. My website has a dynamic component with Lambda Function URL that adds to a Dynamo DB table when my website is viewed. Everything works good, but my problem is I don’t know how to get the function URL after Terraform is complete to automatically update in my javascript file, if this is possible or any other way. Right now, I have to go into the Javascript file and copy and paste the function URL from Lambda after my Terraform has ran, but I would like everything to be fully automated.

My javascript file(XXX= the function url that I have to hardcode):

const counter = document.querySelector(".counter-number"); 
async function updateCounter() {
    let response = await fetch("XXX");
    let data = await response.json();
    counter.innerHTML = `Website View Count: ${data}`;
} 
updateCounter();

The portion of my Terraform where the Javascript file is uploaded to S3- I currently have it to where any change in my website files is picked up through Terraform:

resource "aws_s3_object" "website_contents" {
  for_each     = fileset("/Users/andrea/Documents/AWS/CRC/my_website", "**") 
  bucket       = data.aws_s3_bucket.main_bucket.id
  key          = each.key
  source       = "/Users/andrea/Documents/AWS/CRC/my_website/${each.value}"
  content_type = each.value
  etag = filemd5("/Users/andrea/Documents/AWS/CRC/my_website/${each.value}")
}

Please let me know if there is any thing else I can provide, I appreciate any sort of help and assistance- thank you!

Postman : Reading inputs from csv data file and iterating through each row and form the request body based on mandoty & optional parameter

I have a csv file like below. Where in row1 all the headers value are passed and in the 2nd row countryId is null since it optional.

userName,password,address1,countryId
test1,pass1,lblr,1
test2,pass2,

When i read the csv file in postman pre-request i am getting output as below.

userName: "roxxroyce"
password: "Pass@123"
address1: "LBLR"
countryId: 1

userName: "roxxroyce"
password: "Pass@123"
address1: "RQIP"

Tried the below code login to achieve the expected output. But this seems to be not giving the correct results. Can someone help me with this request?

let lines = iterationData.split('n');
let headers = lines[0].split(',');
let requestBodyArray = [];

for (let i = 1; i < lines.length; i++) {
    let values = lines[i].split(',');
    let userObject = { user: {} };

    for (let j = 0; j < headers.length && j < values.length; j++) {
        let key = headers[j].trim();
        let value = values[j] ? values[j].trim() : ''; // Check if value exists before trimming

        if (value !== "") {
            if (key === "countryId") {
                // Add countryId to the address object
                if (!userObject.user.address) {
                    userObject.user.address = [{ [key]: value }];
                } else {
                    userObject.user.address[0][key] = value;
                }
            } else if (key === "address1") {
                // Add address1 to the address object
                if (!userObject.user.address) {
                    userObject.user.address = [{ [key]: value }];
                } else {
                    userObject.user.address[0][key] = value;
                }
            } else {
                // Add other properties to the user object
                userObject.user[key] = value;
            }
        }
    }

    requestBodyArray.push(userObject);
}

// Log the resulting request body
console.log(JSON.stringify(requestBodyArray, null, 2));

Expected output:

iteration#1:

  {
    "user": {
      "userName": "test1",
      "password": "pass1",
      "address": [
        {
          "address1": "lblr",
          "countryId": "1"
        }
      ]
    }
  }

iteration#2:

      {
        "user": {
          "userName": "test2",
          "password": "pass2"
        }
      }

How to get the connection URL parameters using socket.io

I have a client script that makes calls to this server


var _websocket = new WebSocket(ws://localhost:3000/<param>, ["ocpp1.6", "ocpp1.5"]);

I want to get the message sent from the client using this socket.io server but I haven’t found a way to connect properly and get the parameter.


import { Server } from 'socket.io'

const io = new Server(3000)

io.on('connection', (socket) => {
  console.log('Cliente conectado:', socket.id)

  console.log(socket.handshake.url)
})

Excuse my English, I am not a native speaker.

I saw that there is something called a namespace in socket.io, but they must be defined to connect to that namespace, but what I want is to get the parameter after the slash, which is variable since it is a connection identifier.

OBJ model is not displaying WebGL

I am working on a project using WebGL and I am trying to display a simple OBJ however, nothing gets displayed. Here is why the console says:

Unhandled Model Keyword: mtllib at line 1 loadModel.js:85:21
Unhandled Model Keyword: o at line 2 loadModel.js:85:21
Unhandled Model Keyword: usemtl at line 37 loadModel.js:85:21
Unhandled Model Keyword: s at line 38 loadModel.js:85:21
<empty string> app.js:68:13
<empty string> app.js:74:13
WebGL warning: drawArraysInstanced: Vertex fetch requires 36, but attribs only supply 26. 32
After reporting 32, no further warnings will be reported for this WebGL context.

Here is my code:

index.html:

<!DOCTYPE html>

<html>
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    
    <link href="index.css" rel="stylesheet">
    <link rel="preconnect" href="https://fonts.googleapis.com"><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin><link href="https://fonts.googleapis.com/css2?family=Source+Sans+Pro&display=swap" rel="stylesheet">
    
    <script src="gl-matrix-min.js" defer></script>
    <script type="module" src="app.js" defer></script>
</head>
<body>
    <canvas></canvas>
    <script>
        const c = document.getElementsByTagName("canvas")[0];
        c.width = window.innerWidth;
        c.height = window.innerHeight;
    </script>
</body>
</html>

App.js:

import "./gl-matrix-min.js";
const { mat2, mat2d, mat4, mat3, quat, quat2, vec2, vec3, vec4 } = glMatrix;

import { loadTexture } from "./loadTexture.js"
import { parseOBJ } from "./loadModel.js";
import { loadTextResource, repeat } from "./util.js";

window.onload = function (){
    loadTextResource('/Shaders/shader.vs.glsl', function(vsErr, vsText){
        if(vsErr){
            alert("Error getting vertex shader (check console for more info)");
            console.error(vsErr);
        }else{
            loadTextResource('/Shaders/shader.fs.glsl', function(fsErr, fsText){
                if(fsErr){
                    alert("Error getting fragment shader (check console for more info)");
                    console.error(fsErr);
                }else{
                    RunScene(vsText, fsText);
                }
            });
        }
    });
}
async function RunScene(vsText, fsText){
    const canvas = document.querySelector('canvas');
    const gl = canvas.getContext('webgl');

    if(!gl){
        console.error("WebGL not supported on this browser!");
    }

    const response = await fetch('Models/test.obj');
    const text = await response.text();
    const data = parseOBJ(text);

    //Vertex Data
    const vertexData = data.positions;

    // Image UV Data
    const uvData = data.texCoords;

    // F|L|B|R|T|U
    const normalData = data.normals;

//    console.log(normalData);

    const positionBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexData), gl.STATIC_DRAW);

    const uvBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(uvData), gl.STATIC_DRAW);

    const normalBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(normalData), gl.STATIC_DRAW);

    const picture = loadTexture(gl, `Textures/Pablo.png`);

    gl.activeTexture(gl.TEXTURE0);
    gl.bindTexture(gl.TEXTURE_2D, picture);

    const vertexShader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vertexShader, vsText);
    gl.compileShader(vertexShader);
    console.log(gl.getShaderInfoLog(vertexShader));


    const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fragmentShader, fsText);
    gl.compileShader(fragmentShader);
    console.log(gl.getShaderInfoLog(fragmentShader));

    const program = gl.createProgram();
    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);
    gl.linkProgram(program);

    const positionLocation = gl.getAttribLocation(program, 'position');
    gl.enableVertexAttribArray(positionLocation);
    gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
    gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);

    const uvLocation = gl.getAttribLocation(program, 'uv');
    gl.enableVertexAttribArray(uvLocation);
    gl.bindBuffer(gl.ARRAY_BUFFER, uvBuffer);
    gl.vertexAttribPointer(uvLocation, 2, gl.FLOAT, false, 0, 0);

    const normalLocation = gl.getAttribLocation(program, 'normal');
    gl.enableVertexAttribArray(normalLocation);
    gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
    gl.vertexAttribPointer(normalLocation, 3, gl.FLOAT, false, 0, 0);

    gl.useProgram(program);
    gl.enable(gl.DEPTH_TEST);

    const uniformLocations = {
        matrix: gl.getUniformLocation(program, 'matrix'),
        normalMatrix: gl.getUniformLocation(program, 'normalMatrix'),
        textureLocation: gl.getUniformLocation(program, 'textureID'),
    };


    const modelMatrix = mat4.create();
    const viewMatrix = mat4.create();
    const projectionMatrix = mat4.create();
    mat4.perspective(projectionMatrix, 75 * Math.PI/180, canvas.width/canvas.height, 1e-4, 1e4);

    const mvMatrix = mat4.create();
    const mvpMatrix = mat4.create();

    const normalMatrix = mat4.create();

    mat4.translate(viewMatrix, viewMatrix, [0, 0.01, 2]);
    mat4.invert(viewMatrix, viewMatrix);

    gl.uniform1i(uniformLocations.textureLocation, 0);

    function animate(){
        requestAnimationFrame(animate);

        mat4.rotateX(modelMatrix, modelMatrix, Math.PI/100);
        mat4.rotateY(modelMatrix, modelMatrix, Math.PI/200);

        mat4.multiply(mvMatrix, viewMatrix, modelMatrix);
        mat4.multiply(mvpMatrix, projectionMatrix, mvMatrix);
        
        mat4.invert(normalMatrix, mvMatrix);
        mat4.transpose(normalMatrix, normalMatrix);
        
        gl.uniformMatrix4fv(uniformLocations.matrix, false, mvpMatrix);
        gl.uniformMatrix4fv(uniformLocations.normalMatrix, false, normalMatrix);

        gl.drawArrays(gl.TRIANGLES, 0, vertexData.length/3);
    }

    animate();
}

loadModel.js:

export function parseOBJ(text){
    const objPositions = [[0, 0, 0]];
    const objTexCoords = [[0, 0]];
    const objNormals = [[0, 0, 0]];

    const objVertexData = [
        objPositions,
        objTexCoords,
        objNormals,
    ];
    
    let webglVertexData = [
        [], //Verts
        [], //UV
        [], //Normals
    ];

    function addVertex(vert) {
        const ptn = vert.split('/');
        ptn.forEach((objIndexStr, i) => {
            if (!objIndexStr) {
                return;
            }
            const objIndex = parseInt(objIndexStr);
            const dataArray = objVertexData[i];
    
            if (dataArray && dataArray.length > 0) {
                let index = objIndex > 0 ? objIndex - 1 : dataArray.length + objIndex;
                
                // Ensure the index is within bounds
                index = Math.max(0, Math.min(index, dataArray.length - 1));
    
                const data = dataArray[index];
                if (data !== undefined) {
                    webglVertexData[i].push(...dataArray[index]);
                } else {
                    console.error(`Error: Undefined data at index ${index} for objVertexData[${i}]`);
                }
            } else {
                console.error(`Error: No data found for objVertexData[${i}]`);
            }
        });
    }
    
    
    

    const keywords = {
        v(parts){
            objPositions.push(parts.map(parseFloat));
        },
        vn(parts){
            objTexCoords.push(parts.map(parseFloat));
        },
        vt(parts){
            objNormals.push(parts.map(parseFloat));
        },
        f(parts){
            const numTriangles = parts.length - 2;
            for(let tri = 0; tri < numTriangles; ++tri){
                addVertex(parts[0]);
                addVertex(parts[tri + 1]);
                addVertex(parts[tri + 2]);
            }
        }
    };

    const keywordRE = /(w*)(?: )*(.*)/;
    const lines = text.split('n');
    for(let lineNum = 0; lineNum < lines.length; ++lineNum){
        const line = lines[lineNum].trim();
        if(line === '' || line.startsWith('#')){
            continue;
        }

        const m = keywordRE.exec(line);
        if(!m){
            continue;
        }
        
        const [, keyword, unparsedArgs] = m;
        const parts = line.split(/s+/).slice(1);
        const handler = keywords[keyword];
        if(!handler){
            console.warn('Unhandled Model Keyword:', keyword, 'at line', lineNum + 1);
            continue;
        }
        handler(parts, unparsedArgs);
    }

    return {
        positions: webglVertexData[0],
        texCoords: webglVertexData[1],
        normals: webglVertexData[2]
    };
}

I believe that some of the vertices are not being provided to WebGL however, when I print out the vertices it says the length is 36 and the vertices themselves match the OBJ file’s vertices.

local html site not responsive [closed]

I’m learning js atm. Whenever I try to open my simple html site it won’t load and it says it’s unresponsive. Here’s the code:

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>JS Library</title>
  <meta name="author" content="">
  <meta name="description" content="">
  <meta name="viewport" content="width=device-width, initial-scale=1">

  <link href="css/style.css" rel="stylesheet">
</head>

<body>
<div id="container">
  <h1>Javascript Library</h1>
  <hr>
  <p>What book would you like to add?</p>
  <input id="title">
  <input id="author">
  <input id="pages">
  <input id="read_status">
  <button type="button" onclick="addBookToLibrary()">Submit</button>

  <script src="js/script.js"></script>
</body>
</div>

</html>

Idk if it’s a problem with the actual js or the html. I’ve tried restarting my computer and reloading the browser cache but it still doesn’t work.

Chrome Extension Background onMessage Listener not activating

I have a background.js file for my chrome extension with a message listener and on action.onClicked I want to do some reading on the dom and send the data back to background.js to do further handling. As my code stands, I added a console.log at the beginning of the message handler, but it never activates.

Here is my code:
background.js

const extensions = 'https://leetcode.com/problems';

chrome.action.onClicked.addListener(async (tab) => {
    if (tab.url.startsWith(extensions)) {
        await chrome.scripting.executeScript({
            target: { tabId: tab.id },
            files: ['script.js'],
        });
    }
});

chrome.runtime.onMessage.addListener(function (message, sender, sendResponse) {
    console.log('hi', message);
    if (message.type === 'leetcodescrape') {
        console.log('Received data from content script:', message);
    }
});

script.js

(() => {
    const title = document.querySelector('a.font-medium').innerText;
    const difficulty = document
        .querySelector('.text-sm.font-medium.capitalize')
        .innerText.toLowerCase();
    const currentURL = window.location.href;
    const code = document.querySelector(
        ".view-lines[role='presentation']"
    ).innerText;

    const formattedTitle = title
        .toLowerCase()
        .replace(/[^0-9a-zs]/g, '')
        .replace(/s+/g, '-');

    const storedText = `#${currentURL}n${code}`;

    console.log(formattedTitle, difficulty, currentURL);

    chrome.runtime.sendMessage({
        type: 'leetcodescrape',
        data: { formattedTitle, difficulty, storedText },
    });
})();

Here is my manifest.json if it is helpful:

{
    "manifest_version": 3,
    "name": "leetcode-scraper",
    "description": "by me for me",
    "version": "1.0",
    "icons": {
        "16": "icon.png"
    },
    "background": {
        "service_worker": "background.js"
    },
    "action": {
        "default_icon": "icon.png"
    },
    "permissions": [
        "tabs",
        "nativeMessaging",
        "activeTab",
        "scripting",
        "downloads"
    ],
    "commands": {
        "_execute_action": {
            "suggested_key": {
                "default": "Ctrl+B",
                "mac": "Command+B"
            }
        }
    }
}

I have previous moved the external script into the file and made it a function and added the console.log line in the onmessage handler.

How can I get my MUI Typography component to render a custom image cursor on hover?

I tested setting the cursor to cursor: pointer which works fine, but I would like to use a custom image as a cursor. The image is stored in my src folder and I tried it in the public folder as well. I’m assuming I’m messing something up with the sytnax on "url(JavaScript-logo.png)"

  <Typography
        sx={{
          "&:hover": { cursor: "url(JavaScript-logo.png), auto" },
        }}
      >
        ["JavaScript",
  </Typography>

I have also tried it without the &:hover, and without auto

REACT: How to update the information in initialState: {} in @reduxjs/toolkit

In a createSlice component, I am trying to call a reducers function that changes a part of the initialState but when I call it, the console.log(state) in the function looks like this:

Proxy { <target>: {…}, <handler>: {…} }
<target>: null
<handler>: null

The console.log(current(state)) in the function looks like this:

Object { type: "div", key: null, ref: null, props: {…}, _owner: null, _store: {}, status: "currency succeeded", currencies: (7) […], error: "Request aborted" }
_owner: null
_store: Object {  }
currencies: Array(7) [ {…}, {…}, {…}, … ]
error: "Request aborted"
key: null
props: Object { children: "CurrencySlice" }
ref: null
status: "currency succeeded"
type: "div"
<prototype>: Object { … }

This is where I am calling it from:

import { useEffect } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { fetchCurrencies, setCurrency } from './slices/CurrencySlice';


const DispatchAll = () => {
  const dispatch = useDispatch();
  const { currencies, status: currencyStatus, error: currencyError, selected: currentCurrency  } = useSelector((state) => state.currency);


  useEffect(() => {
    dispatch(fetchCurrencies())
    // Below this does not work either
    // dispatch(fetchCurrencies()).then(() =>{
      // dispath(setCurrency('USD'))
    // });
  }, [dispatch]);


  if (currencyStatus === 'currency loading') {
    console.log('currency loading')
  }

  if (currencyStatus === 'currency failed') {
    console.log('currency failed')
  }
  
  if (currencyStatus === 'currency succeeded') {
    console.log('currency succeeded')
    dispatch(setCurrency('USD'))
  }

  return null
}

export default DispatchAll

This is what the createSlice looks like:

import axios from "axios";
import { createSlice, createAsyncThunk, current } from "@reduxjs/toolkit";

const CURRENCIES = 'location'

export const fetchCurrencies = createAsyncThunk('currency/fetchCurrencies', async () => {
  try {
    const response = await axios.get(CURRENCIES)
    return response.data
  } catch (error) {
    throw error
  }
})

const CurrencySlice = createSlice({
  name: 'currencies',
  initialState: {
    currencies: [],
    status: 'idle',
    error: null,
    selected: {
      id: '',
      name: '',
      symbol: '',
      rate: 1,
    }
  },
  reducers: {
    setCurrency: (state, action) => {
      console.log(state)
      console.log(current(state))

      const currencyName = action.payload;
      const foundCurrency = state.currencies.find(currency => currency.name === currencyName)

      if (foundCurrency) {
        state.selected = {
          id: foundCurrency.id,
          name: foundCurrency.name,
          symbol: foundCurrency.symbol,
          rate: foundCurrency.rate,
        };
      }
    }
  },
  extraReducers: (builder) => {
    builder
      .addCase(fetchCurrencies.pending, (state) => {
        state.status = 'currency loading'
      })
      .addCase(fetchCurrencies.fulfilled, (state, action) => {
        state.status = 'currency succeeded'
        state.currencies = action.payload
      })
      .addCase(fetchCurrencies.rejected, (state, action) => {
        state.status = 'currency failed'
        state.error = action.error.message
      })
  },
})

export const { setCurrency } = CurrencySlice.actions
export default CurrencySlice.reducer

How to execute a function after another function is complete in reactjs

So I have a button that I want to execute two animation functions when clicked but I want to execute the second one only after the first one is complete

<button
        onClick={() => {
          animate(nodesVisitedInOrder);
          animate(path); // I want to execute this function only after the prev one is complete
        }}
   >

I tried to put the second function in a setTimeOut like so, but they are still running at the same time.

<button
        onClick={() => {
          animate(nodesVisitedInOrder); 
         setTimeout(() => animate(path), 1000);
        }}
   >

Here’s the animation function:

 const animate = (nodes) => {
        for (let i = 0; i < nodes.length; i++) {
        setTimeout(() => {
            const node = nodes[i];
            setTable((prev) => {
            const newArray = [];
            for (var i = 0; i < prev.grid.length; i++) {
                newArray[i] = prev.grid[i].slice();
            }
            return {
                ...prev,
                grid: newArray.map((items) =>
                items.map((item) => {
                    const { row, col } = item.pos;
                    return row === node.row && col === node.col
                    ? { ...item, isAnimate: !item.isAnimate }
                    : item;
                })
                ),
            };
            });
        }, 10 * i);
        }
    };

Tabulator: How to add new row which merge multiple columns on tabulator

Is there any way to add new row which will merge multiple columns on tabulator?

enter image description here Something like this, data needs to be spanned on multiple columns.

Other details are added from the ajax call or some other functions, i need to add new row which have some cell spanning multiple columns. The cell not only contains price or something like that it may contains other things too. so calculation is not required.

Is there any way to solve this problem? Maybe by adding footer or other things to achieve this.

I am using typescript, so it will be very helpful if the solution is provided on the typescript.

Thank you very much.

How to use chart.js from CDN?

Chart displays when I copy and paste HTML under Create a Chart section in https://www.chartjs.org/docs/latest/getting-started/

But when I cut the code under script tag, paste it in a js file (test.js) at the same location as html file, and replace that script tag with <script src="test.js"></script>, it does not work.

<script src="./test.js"></script> doesnt work either.

Adding type=”text/javascript” doesnt work either.

What wrong am I doing?