Facing problem while using map function in react [duplicate]

have a React component. It loads a local JSON file. In the constructor I want to loop through the local JSON file, find an item that matches a URL parameter, and set some state values. Here is my code so far:

import React,{Component} from "react";

import topics from './topics.json';

class Tutorial extends Component {

  constructor(props){
    super(props);

    topics.map((topic, index) => {

      if(topic.url === this.props.match.params.url)
      {
        this.state = {
          url: this.props.match.params.url,
          name: topic.name
        };
      }
    })
  }

  render() {
    return (
      <div className="Tutorial">

        <div className="ca-nav-spacer w3-hide-small"></div>

          {this.state.name}
          {this.state.url}

      </div>
    );
  }
}

export default Tutorial;

I keep getting this error: Array.prototype.map() expects a return value from arrow function.

Must the map function return a value? If I’m not returning a value should I just use a for loop? Can I return the block of JSON and then set the state after the map? What would be the proper way to do this?

Display Issue with @vuepic/vue-datepicker: Seeking Solutions

I am using the @vuepic/vue-datepicker library to manage 3 datepicker instances in my project, namely:

  • Date + Time
  • Date
  • Time

However, the last one is not functioning as expected.

When I call my component with a default value, it is not displayed on the screen! Here is the source code for my component:

<template>
  <Datepicker 
    v-model="time"
    :name="name"
    :defaultvalue="defaultvalue"
    time-picker
    cancelText="Cancel"
    selectText="Select"
  />
</template>

<script>
import { defineAsyncComponent, ref } from 'vue';
import '@vuepic/vue-datepicker/dist/main.css';

export default {
  components: {
    Datepicker: defineAsyncComponent(() => import('@vuepic/vue-datepicker')),
  },
  props: {
    defaultvalue: {
      type: String,
      required: true
    },
    name: {
      type: String,
      required: true
    }
  },
  /**
   * Sets up the component based on the provided props.
   *
   * @param {object} props - The props object passed to the component.
   * @return {object} - An object containing the `time` property.
   */
  setup(props) {
    const timeString = props.defaultvalue;
    let time = ref();

    if (timeString !== '') {
      const [hours, minutes, seconds] = timeString.split(':').map(Number);
      time = ref({
        hours: hours,
        minutes: minutes,
        seconds: seconds
      });
    }

    return {
      time,
    };
  },
};
</script>

Does anyone have an idea why?

Thanks in advance.

How do you troubleshoot JSDOM’s ResourceLoader?

I’m loading this html in JSDOM:

./template.html

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>title</title>
  </head>
  <body>
    <div>hi</div>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <script>
        console.log(`2nd script: Does window.$ exist?`, window.$ !== undefined && window.$ !== null);
        console.log(`2nd script: Does $ exist?`, $ !== undefined && $ !== null);
    </script>
  </body>
</html>

My question is, how do I know if a resource (e.g., https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js) was successfully loaded? That url is simply an example. I’m asking in general.

Here is the rest of my project structure:

Project Structure

.
├── .eslintrc.json
├── .prettierrc
├── index.js
├── package.json
└── template.html

./index.js

/* eslint-disable no-unused-vars */
import { JSDOM, ResourceLoader } from 'jsdom';

class CustomResourceLoader extends ResourceLoader {
  fetch(url, options) {
    console.log(`Called with ${url}`);

    return super.fetch(url, options); // was the resource loaded correctly?
  }
}

const dom = await JSDOM.fromFile(`./template.html`, {
  url: 'http://localhost',
  runScripts: 'dangerously',
  resources: new CustomResourceLoader(),
  pretendToBeVisual: true,
});

const window = dom.window;

const $1 = window.eval('window.$');
console.log(
  `jsdom module: Does window.$ exist?`,
  $1 !== undefined && $1 !== null
);

./package.json

{
  "name": "jsdom-sandbox",
  "version": "0.0.1",
  "description": "A simple sandbox for playing around with jsdom.",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "test": "npm run exec && jasmine",
    "exec": "node index.js"
  },
  "devDependencies": {
    "@types/jasmine": "^5.1.1",
    "@types/jquery": "^3.5.25",
    "@types/jsdom": "^21.1.4",
    "eslint": "^8.52.0",
    "eslint-config-prettier": "^9.0.0",
    "eslint-plugin-prettier": "^5.0.0",
    "jasmine": "^5.1.0"
  },
  "dependencies": {
    "@prettier/sync": "^0.3.0",
    "jsdom": "^22.1.0",
    "prettier": "^3.0.3"
  }
}

Is there a way to reinitialize jQuery?

Question

Jquery is initialized on import. If document exists, it saves its reference and uses it thereafter. If document is undefined, it throws an error.

Is there a way I can “reinitialize” or “reset” jquery after it’s been imported so it uses a new reference to document?


Context

I’m working on a frontend-only, single page app project. Even though the project runs exclusively in the browser, the automated tests run in Node.JS. The tests load the html in JSDOM and execute portions of the production code.1

On creation, JSDOM returns a DOM API that works in Node.JS, including a window object. Without this, jQuery will error on import because modern versions have code like this:

(function(global, factory) {

    "use strict";
  
    if (typeof module === "object" && typeof module.exports === "object") {
  
      // For CommonJS and CommonJS-like environments where a proper `window`
      // is present, execute the factory and get jQuery.
      // For environments that do not have a `window` with a `document`
      // (such as Node.js), expose a factory as module.exports.
      // This accentuates the need for the creation of a real `window`.
      // e.g. var jQuery = require("jquery")(window);
      // See ticket trac-14549 for more info.
      module.exports = global.document ?
        factory(global, true) :
        function(w) {
          if (!w.document) {
            throw new Error("jQuery requires a window with a document");
          }
          return factory(w);
        };
    } else {
      factory(global);
    }
  
    // Pass this if window is not defined yet
  })(typeof window !== "undefined" ? window : this, function(window, noGlobal) {
    console.log(`window`, window);
    console.log(`noGlobal`, noGlobal);
  })
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

As you can see, this executes as a side effect of importing jQuery. This has caused considerable headache because it isn’t always straightforward to create JSDOM before importing jQuery. For example, if the production code imports jQuery and the test imports the production code, JSDOM (and therefore window) won’t exist yet. This throws an error.


Notes

For the record, I’m using jQuery 3.7.1, but stackoverflow code snippets don’t give me the option to pick that version. I think that’s fine because, as far as I can tell, this code is the same in both.

1: Unfortunately, that means going against the official JSDOM advice. But in this context, I can’t see a way around that.

Hitting Presigned URL to download object and get access denied exception

In our code base, we are aiming to render the S3 GetObject SignedURL for the client, so the client can download the object by clicking the url in the website .

Here is the v2 code:

return s3Client.getSignedUrlPromise('getObject', {
           ...UDMSController.parseS3URI(s3URI),
           Expires: config.udms.s3.signedURLTTL,
         });

Here is the upgraded V3 code

const getObjectParams: GetObjectCommandInput = { Bucket: parsedS3URI.host, Key: parsedS3URI.pathname.substr(1) };
const command = new GetObjectCommand(getObjectParams);
return await getSignedUrl(s3Client, command, {expiresIn: config.udms.s3.signedURLTTL});

The IAM role we are assuming is the external account S3 permission role, here is the their S3 permission, basically, they did not change their permission

{
   "s3:Put*",
   "s3:List*",
   "s3:Get*",
}

And the client hit the URL we render on the website, they get accessDenied exception.

Here is the failed request

https://ring-data-requests-dev.s3.us-east-1.amazonaws.com/gdpr/exports/user-46364072/10001357/datarequest.zip?

X-Amz-Algorithm=AWS4-HMAC-SHA256&

X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&

X-Amz-Credential=ASIA5JGQ37JDTMSI4DYI%2F20231204%2Fus-east-1%2Fs3%2Faws4_request&

X-Amz-Date=20231204T180657Z&

X-Amz-Expires=600&

X-Amz-Security-Token=IQoJb3JpZ2luX2VjEPv%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEaCXVzLWVhc3QtMSJHMEUCIAc91WgOnR7Ry7tFwAN3bxAcwnZU3ehq2ENWm20MmevEAiEAhABAuMGiuVdcP6F7L%2BCqltrVh8%2FibtD2Z8uHa%2Ff2sR4qogIIYxADGgw5MTMxMTg1OTE1NTkiDGl7KMFE0%2BweJIPx4ir%2FAaO6C2bV7YLDAOR8EeYLwWA3jErDB9alj77gDoBNSbow6EMla3rLwXD2DbGN6k2tc6L8E2fGbbYenVMwGYt1Er%2Bf1pmXknqMgkhl7XpE3vq8HIIA7gTq%2BzKnfkLkILzJ2KcV%2BydA4%2Fzf7OphnHUgxCs30aAnG7cG1V3v2QVyWAd13%2Bx0evHww2GnZZeCcs9oAb4iZnmgg96kvfGOejGprshhQh83BB299T4336LOmpcByFz5fDxecmcOzMd%2Bmb4cqCuDDmMCsIhJ9nzve5hmZVv3hNuOonum6ROPHEzvAw17qMK7hhUL3Qn0vQjg6m6VIfbVAU1zXJg2AXROg6br7TDBqrirBjqdAQKuiFH5cVTfh2G1dLDtJkVQr5%2F2zCuBY20VQ3%2FTuYNtecpL%2FV%2BzDUIJiEcjgVboeMG%2F9%2BLbjwgrKBI7G0h0%2BqQ%2F4C0Ew9q4mPQmkcEUFahKMPLVU0w9sLJE07kfKfa8o6WlOoE4HM1WLm0SnEUswLy6F1M%2BKVqB%2FDP3J8xvIxO2nB0yhEkwTctP1%2BtBBSfG4ynAAvJgLC8e00dgzwc%3D&

X-Amz-Signature=08870a418d16e84832b20b44b1a9b7bc47dd0cc8193c4084831a99c7668a5800&

X-Amz-SignedHeaders=host&

x-id=GetObject

The sample S3 path is:

s3://ring-data-requests-dev/gdpr/exports/user-82032267/10001355/datarequests.zip

We can get the URL and S3Path without error in our side, the issue is client keep getting accessDenied.

Does anyone know for this kind of upgrade, will the S3 role need extra permission? Or in our code base that we are missing any setup?

My assumption is the new SDK version let the request X-Amz-Content-Sha256 be assigned as UNSIGNED-PAYLOAD and the bucket might reject reqeust with UNSIGNED-PAYLOAD content. Appreciate for any helps and hints here.

Thanks!

Expect the client won’t face the accessDenied issue, Tried with grant the source s3 bucket with full S3 permission but still get the same issue.

when collection is converted to json, query property have weird schema

I have tried 2 ways to do this both resulted in same

Directly manipulating url

    const request = new Request({
      header: requestHeader,
      url: `${apiEndpoint}?${new URLSearchParams(params).toString()}}`,
      method: 'GET',
      auth: null,
    });

using QueryParam

    Object.keys(params).forEach((key) => {
      const queryParams = new QueryParam({
        key,
        value: params[key],
      });
      request.addQueryParams(queryParams);
    });

both result into query property like this

"query": [
    {
        "key": "members",
        "value": {
            "prop1": {
                "key": "keyName",
                "value": "VALUE"
            },
            "prop2": {
                "key": "keyName2",
                "value": "VALUE2"
            },
        ]
    },
    {
        "key": "reference",
        "value": {
            "prop1": {
                "key": "keyName",
                "value": "VALUE"
            },
            "prop2": {
                "key": "keyName2",
                "value": "VALUE2"
            },
        }
    },
    {
        "key": "Type",
        "value": {
            "_postman_propertyName": "QueryParam",
            "_postman_propertyIndexKey": "key",
            "_postman_propertyAllowsMultipleValues": true
        }
    },
    {
        "key": "_postman_listIndexKey",
        "value": "key"
    },
    {
        "key": "_postman_listAllowsMultipleValues",
        "value": true
    }
],

when this data is imported into postman it results in this url
{{url}}?members&reference&Type&_postman_listIndexKey=key&_postman_listAllowsMultipleValues

I cross checked by exporting postman collection and there query is array of objects

{
    "key": "KEY1",
    "value": "VALUE1"
},
{
    "key": "KEY2",
    "value": "VALUE2"
},

This happens when using collection.toJSON(), when request.toJSON() is used it in expected format.

Javascript extend parent don’t update field [duplicate]

I have a simple example of a Javascript class with a single method _init
The second class ClassA extends class Parent

If i try to update an property of the ClassA inside _init method, it doesn’t work.

This is a JsFiddle: https://jsfiddle.net/gwsq615e/

In my exmaple, _varTest is still undefined, but i already change the value in the _init method from ClassA.

I don’t understand why the value of _varTest is not test, but undefined, because _init method is already called in the constructor of class Parent.

How can I get a dynamic canvas element to sit behind other content within an offset div?

I’m using granim.js to generate a dynamically moving gradient in a canvas. I’d like to have it be the background content for a div element. Because granim.js generates content dynamically, using canvas.toDataUrl() doesn’t work, and setting position to absolute or relative and setting top/bottom/left/right to 0 doesn’t work, because the div is offset from the edge of the screen. I could calculate the absolute position using .getBoundingClientRect() and setting top that way (see bottom), but I felt like there had to be a more elegant solution. I’ve attached some code snippets below that hopefully help. Thanks!

HTML:

<main>
  <div class="wrapper">
    <div class="granim-wrapper">
      <canvas id="granim-canvas" height="565" width="837"></canvas>
    </div>

    <h1>This is some content.</h1>
  </div>
</main>

CSS:

body {
  width: 100%;
  height: 100%;
  margin-right: auto;
  margin-left: auto;
  display: flex;
  flex-direction: column;
}

main {
  margin: 30px;
  flex-grow: 1;
  border: 1px solid black;
}

canvas {
  display: block;
  z-index: -1;
}

JS:

import Granim from "granim";

function resizeCanvas(canvas: HTMLCanvasElement) {
  const main = document.querySelector('main');

  canvas.height = main.clientHeight;
  canvas.width = main.clientWidth;
}

const canvas = document.getElementById('granim-canvas') as HTMLCanvasElement;
window.onresize = () => {resizeCanvas(canvas)};

window.onload = () => {
  resizeCanvas(canvas)

  const granimInstance = new Granim({
    element: "#granim-canvas",
    name: "granim",
    opacity: ["1", "1"],
    states: {
      "default-state": {
        gradients: [
          ["#8093F1", "#FDC5F5"],
          ["#B388EB", "#72DDF7"],
        ],
        loop: true,
      },
    },
    direction: 'diagonal',
  });
};

Solution using .getBoundingClientRect():

const main = document.querySelector('main');
const rect = main.getBoundingClientRect();
const canvas = document.getElementById('granim-canvas');

canvas.style.top = `${rect.top}px`;

How to count a single specific tile in a grid with divs having the same class

We want to count the grid tiles like in the bottom example, but in a more efficient way. like if we want to add 100 grid tiles instead of 9

HTML:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="css/main.css">
    
    
    <title>puzzle</title>
</head>
<body>
    <div class="main_container"> 
            <div id="grid1" class="grid-item slika1">1</div>
            <div id="grid2" class="grid-item slika1">2</div>
            <div id="grid3" class="grid-item slika1">3</div>
            <div id="grid4" class="grid-item slika1">4</div>
            <div id="grid5" class="grid-item slika1">5</div>
            <div id="grid6" class="grid-item slika1">6</div>
            <div id="grid7" class="grid-item slika1">7</div>
            <div id="grid8" class="grid-item slika1">8</div>
            <div id="grid9" class="grid-item slika1">9</div>
    </div>

    
</div>
    
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <script src="js/script.js" type="text/javascript"></script>
</body>
</html>

CSS:

body {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100vh;
    margin: 0;
}


.main_container{
    width: 60%;
    height: 80%;
    background-size: cover;
    background-position: center;
    display: grid;
    grid-template-columns: auto auto auto;
    position: absolute;
}

.grid-item {
    background-attachment: fixed;
    opacity: 1;
    border: 1px solid rgba(0, 0, 0, 0.8);
    padding: 20px;
    font-size: 30px;
    text-align: center;
    background-size: cover;
    
}


.slika1{
  background-image: url("/images/narava2.jpg");
}

.slika2{
  background-image: url("/images/cat.jpg");
}

.slika3{
  background-image: url("/images/food-spread.jpg");
}

JS:

console.log("connected");
var clicks1=0,clicks2=0,clicks3=0,clicks4=0,clicks5=0,clicks6=0,clicks7=0,clicks8=0,clicks9=0,i=0;
var clikcs=[clicks1,clicks2,clicks3,clicks4,clicks5,clicks6,clicks7,clicks8,clicks9];


$(".grid-item").click(function(){
    clicks1++;
    
     console.log("clicked "+ clicks1);
     i=clicks1%3;

     if(i===1){
        $(this).removeClass("slika1")
        $(this).removeClass("slika3")
        $(this).addClass("slika2") 
     }else if(i===2){
        $(this).removeClass("slika2")
        $(this).removeClass("slika1")
        $(this).addClass("slika3") 
     }else{
        $(this).removeClass("slika3")
        $(this).removeClass("slika2")
        $(this).addClass("slika1") 
     }
})






// bottom example

/*
$("#grid1").click(function(){
    clicks1++;
    
    // console.log("clicked "+ clicks);
     i=clicks1%3;

     if(i===1){
        $(this).removeClass("slika1")
        $(this).removeClass("slika3")
        $(this).addClass("slika2") 
     }else if(i===2){
        $(this).removeClass("slika2")
        $(this).removeClass("slika1")
        $(this).addClass("slika3") 
     }else{
        $(this).removeClass("slika3")
        $(this).removeClass("slika2")
        $(this).addClass("slika1") 
     }
})

$("#grid2").click(function(){
    clicks2++;
    
    // console.log("clicked "+ clicks);
     i=clicks2%3;

     if(i===1){
        $(this).removeClass("slika1")
        $(this).removeClass("slika3")
        $(this).addClass("slika2") 
     }else if(i===2){
        $(this).removeClass("slika2")
        $(this).removeClass("slika1")
        $(this).addClass("slika3") 
     }else{
        $(this).removeClass("slika3")
        $(this).removeClass("slika2")
        $(this).addClass("slika1") 
     }
})
$("#grid3").click(function(){
    clicks3++;
    
    // console.log("clicked "+ clicks);
     i=clicks3%3;

     if(i===1){
        $(this).removeClass("slika1")
        $(this).removeClass("slika3")
        $(this).addClass("slika2") 
     }else if(i===2){
        $(this).removeClass("slika2")
        $(this).removeClass("slika1")
        $(this).addClass("slika3") 
     }else{
        $(this).removeClass("slika3")
        $(this).removeClass("slika2")
        $(this).addClass("slika1") 
     }
})
$("#grid4").click(function(){
    clicks4++;
    
    // console.log("clicked "+ clicks);
     i=clicks4%3;

     if(i===1){
        $(this).removeClass("slika1")
        $(this).removeClass("slika3")
        $(this).addClass("slika2") 
     }else if(i===2){
        $(this).removeClass("slika2")
        $(this).removeClass("slika1")
        $(this).addClass("slika3") 
     }else{
        $(this).removeClass("slika3")
        $(this).removeClass("slika2")
        $(this).addClass("slika1") 
     }
})
$("#grid5").click(function(){
    clicks5++;
    
    // console.log("clicked "+ clicks);
     i=clicks5%3;

     if(i===1){
        $(this).removeClass("slika1")
        $(this).removeClass("slika3")
        $(this).addClass("slika2") 
     }else if(i===2){
        $(this).removeClass("slika2")
        $(this).removeClass("slika1")
        $(this).addClass("slika3") 
     }else{
        $(this).removeClass("slika3")
        $(this).removeClass("slika2")
        $(this).addClass("slika1") 
     }
})
$("#grid6").click(function(){
    clicks6++;
    
    // console.log("clicked "+ clicks);
     i=clicks6%3;

     if(i===1){
        $(this).removeClass("slika1")
        $(this).removeClass("slika3")
        $(this).addClass("slika2") 
     }else if(i===2){
        $(this).removeClass("slika2")
        $(this).removeClass("slika1")
        $(this).addClass("slika3") 
     }else{
        $(this).removeClass("slika3")
        $(this).removeClass("slika2")
        $(this).addClass("slika1") 
     }
})
$("#grid7").click(function(){
    clicks7++;
    
    // console.log("clicked "+ clicks);
     i=clicks7%3;

     if(i===1){
        $(this).removeClass("slika1")
        $(this).removeClass("slika3")
        $(this).addClass("slika2") 
     }else if(i===2){
        $(this).removeClass("slika2")
        $(this).removeClass("slika1")
        $(this).addClass("slika3") 
     }else{
        $(this).removeClass("slika3")
        $(this).removeClass("slika2")
        $(this).addClass("slika1") 
     }
})
$("#grid8").click(function(){
    clicks8++;
    
    // console.log("clicked "+ clicks);
     i=clicks8%3;

     if(i===1){
        $(this).removeClass("slika1")
        $(this).removeClass("slika3")
        $(this).addClass("slika2") 
     }else if(i===2){
        $(this).removeClass("slika2")
        $(this).removeClass("slika1")
        $(this).addClass("slika3") 
     }else{
        $(this).removeClass("slika3")
        $(this).removeClass("slika2")
        $(this).addClass("slika1") 
     }
})
$("#grid9").click(function(){
    clicks9++;
    
    // console.log("clicked "+ clicks);
     i=clicks9%3;

     if(i===1){
        $(this).removeClass("slika1")
        $(this).removeClass("slika3")
        $(this).addClass("slika2") 
     }else if(i===2){
        $(this).removeClass("slika2")
        $(this).removeClass("slika1")
        $(this).addClass("slika3") 
     }else{
        $(this).removeClass("slika3")
        $(this).removeClass("slika2")
        $(this).addClass("slika1") 
     }
})*/




The problem is that the variable that is counting the clicks is counted for every click in the div instead of for the specific tile. We tried a lot of things, but we couldn’t figure it out, sadly.

Scrolling zoom effect for text

I recently came across an impressive visual effect on a website and was wondering how I could implement it in my own web application. The effect is as follows: as you scroll down the page, the text gradually zooms in until it reaches a certain maximum size, at which point another element appears.

I’ve tried searching on Google using various keywords such as “scroll zoom effect,” “text zoom on scroll,” “reveal element on scroll,” etc., but I haven’t found a clear guide or example of implementation.

I would greatly appreciate it if someone could guide me or share information on how I could achieve this effect using HTML, CSS, and JavaScript. Whether it’s using an existing library or writing the code from scratch, any advice or links to relevant resources would be welcomed.

To help you better understand what I’m looking for, I found a video that demonstrates exactly the effect I want:

].

Thank you in advance for any help and guidance!

how to unhide a button [closed]

The button is created thus (within a top-level div):

<button id="quit" onclick="Exit()" hidden >Exit</button>

but the following code (though definitely invoked) does not show the button:

document.getElementByID('quit').removeAttribute('hidden');

All my tinkering has failed, with MicroSoft Edge Tools always reporting (unreasonably?):

Uncaught Type Error: document.getElementByID is not a function

Intelephense / Livewire – Decorators are not valid here

I’m using the vscode intelephense extension, and writing some JS logic using laravel livewire. My objective is to send an event at a specific time to refresh some data.

To achieve this, my logic is something like:

document.addEventListener('livewire:load', function () {
    const refreshTime = @this.refreshTime;
    setTimeout(() => {
        Livewire.emit('refresh');
    }, refreshTime);
});

Although this works, the Intelephense extension reports an error on @this.refreshTime:

Decorators are not valid here.javascript
Expression expected.javascript

Is there any way to prevent or ignore this error? I’m thinking something like eslint-disable-next-line, but for intelephense. Solutions that avoid using @this, @js, and other invalid JS syntax would also be acceptable!

React & Jest: Unable to find an element after wrapping with act

I am currently learning how to test React component using Jest. I created a simple Login Form and write the below test.

import { render, screen } from "@testing-library/react";
import "@testing-library/jest-dom";
import { LoginForm } from "./login-form";
import { act } from 'react-dom/test-utils';

describe("LoginForm", () => {
    it("should render", () => {
        // GIVEN

        // WHEN
        render(<LoginForm />);

        // THEN
        expect(screen.getByText("Sign In")).toBeInTheDocument();
    });

    it("should execute submit on button click and valid input", () => {
        // GIVEN
        const onSubmit = jest.fn();

        // WHEN
        render(<LoginForm onSubmit={onSubmit} />);
        screen.getByText("Sign In").click();
        
        // THEN
        expect(onSubmit).toHaveBeenCalled();
    });
});

After I run using Jest, it shows passing tests.

 PASS  src/app/login/login-form.spec.tsx
  LoginForm
    ✓ should render (22 ms)
    ✓ should execute submit on button click and valid input (35 ms)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        0.638 s, estimated 1 s

Interesting thing is that there is a warning above the pass message that I should wrap using act(...).

Warning: An update to LoginForm inside a test was not wrapped in act(...).
    
    When testing, code that causes React state updates should be wrapped into act(...):
    
    act(() => {
      /* fire events that update state */
    });
    /* assert on the output */
    
    This ensures that you're testing the behavior the user would see in the browser. Learn more at https://reactjs.org/link/wrap-tests-with-act

Then I tried wrapping the code using act(...) according the link, like below

import { act } from 'react-dom/test-utils';

//////
    it("should execute submit on button click and valid input", () => {
        // GIVEN
        const onSubmit = jest.fn();

        // WHEN
        act(() => {
            render(<LoginForm onSubmit={onSubmit} />);
            screen.getByText("Sign In").click();
        });

        // THEN
        expect(onSubmit).toHaveBeenCalled();
    });

It suddenly fails with below output,

LoginForm
    ✓ should render (22 ms)
    ✕ should execute submit on button click and valid input (2 ms)

  ● LoginForm › should execute submit on button click and valid input

    TestingLibraryElementError: Unable to find an element with the text: Sign In. This could be because the text is broken up by multiple elements. In this case, you can provide a function for your text matcher to make your matcher more flexible.

    Ignored nodes: comments, script, style
    <body>
      <div />
    </body>

      22 |         act(() => {
      23 |             render(<LoginForm onSubmit={onSubmit} />);
    > 24 |             screen.getByText("Sign In").click();
         |                    ^
      25 |         });
      26 |
      27 |         // THEN

Why it happened, what did I miss, and how to fix this?

Javascript layout not working on mobile, only desktop

Im having trouble with my JS-code. I write in VSC, and use Chrome as browser. in the “preview” everything looks as it should, but when I upload the webpage, the JS-functions only show as it should on a desktop, not on cellphones. Why is this?

I got several boxes sorted by date with JS. So the closer the date, the higher up the box comes. And when the date has passed, the box goes away.

I really can´t figure it out. Should´nt it work on all devices if it is functional? How do I fix this issue? Chrome should support JS by now?

// Thanks!

The site: www.skjerdetnokke.no (work in progress of course, and in Norwegian, but you´ll see what I mean when you open in both desktop and cellphone)

My JS-code:

document.addEventListener('DOMContentLoaded', function () {
  // Select all div elements with the class 'container'
  var divs = document.querySelectorAll('.container');
  // Convert the NodeList to an array for easier manipulation
  var divArray = Array.from(divs);
  // Sort the array based on the data-time attribute
  divArray.sort(function (a, b) {
    var timeA = new Date(a.getAttribute('data-time'));
    var timeB = new Date(b.getAttribute('data-time'));
    return timeA - timeB;
  });
  // Clear the existing order of divs
  divs.forEach(function (div) {
    return div.remove();
  });
  // Append the divs in the new order
  var grid = document.querySelector(".grid");
  divArray.forEach(function (div) {
    return grid.appendChild(div);
  });
});
// Get the current date
var currentDate = new Date();
// Get all grid items
var gridItems = document.querySelectorAll(".container");
// Loop through each grid item
gridItems.forEach(function (item) {
  // Get the date from the data attribute
  var itemDate = new Date(item.getAttribute("data-time"));
  // Compare dates
  if (currentDate > itemDate) {
    // If the current date is after the item date, remove the item
    item.remove();
  }
});