Cookie Consent by Free Privacy Policy Generator Update cookies preferences 📌 Implement React v18 from Scratch Using WASM and Rust - [9] Unit Test with Jest

🏠 Team IT Security News

TSecurity.de ist eine Online-Plattform, die sich auf die Bereitstellung von Informationen,alle 15 Minuten neuste Nachrichten, Bildungsressourcen und Dienstleistungen rund um das Thema IT-Sicherheit spezialisiert hat.
Ob es sich um aktuelle Nachrichten, Fachartikel, Blogbeiträge, Webinare, Tutorials, oder Tipps & Tricks handelt, TSecurity.de bietet seinen Nutzern einen umfassenden Überblick über die wichtigsten Aspekte der IT-Sicherheit in einer sich ständig verändernden digitalen Welt.

16.12.2023 - TIP: Wer den Cookie Consent Banner akzeptiert, kann z.B. von Englisch nach Deutsch übersetzen, erst Englisch auswählen dann wieder Deutsch!

Google Android Playstore Download Button für Team IT Security



📚 Implement React v18 from Scratch Using WASM and Rust - [9] Unit Test with Jest


💡 Newskategorie: Programmierung
🔗 Quelle: dev.to

Based on big-react,I am going to implement React v18 core features from scratch using WASM and Rust.

Code Repository:https://github.com/ParadeTo/big-react-wasm

The tag related to this article:v9

A mature and stable man library like big-react-wasm definitely needs unit tests. So, in this article, we will pause the feature development for now and add unit tests to big-react-wasm. The goal this time is to run the 17 test cases provided by the react official documentation for ReactElement.

Since the test case code runs in a Node environment, we need to modify our build output. First, let's add a new script:

"build:test": "node scripts/build.js --test",

Next, let's add handling for --test in our build.js file. There are two main points to consider. First, we need to change the output target of wasm-pack to nodejs:

execSync(
  `wasm-pack build packages/react --out-dir ${cwd}/dist/react --out-name jsx-dev-runtime ${
    isTest ? '--target nodejs' : ''
  }`
)

In react-dom/index.js, the statement that imports updateDispatcher from react needs to be changed to the commonjs format:

isTest
  ? 'const {updateDispatcher} = require("react");\n'
  : 'import {updateDispatcher} from "react";\n'

After setting up the Jest environment, we'll copy the ReactElement-test.js file from big-react and modify the module import paths:

// ReactElement-test.js
React = require('../../dist/react')
ReactDOM = require('../../dist/react-dom')
ReactTestUtils = require('../utils/test-utils')

// test-utils.js
const ReactDOM = require('../../dist/react-dom')

exports.renderIntoDocument = (element) => {
  const div = document.createElement('div')
  return ReactDOM.createRoot(div).render(element)
}

When executing jest, you may notice that several test cases fail due to the following issues:

  • Type of REACT_ELEMENT_TYPE

Since REACT_ELEMENT_TYPE in big-react-wasm is of type string, we need to modify these test cases accordingly:

it('uses the fallback value when in an environment without Symbol', () => {
  expect((<div />).$$typeof).toBe('react.element')
})

This difference will also affect the execution of the following test case:

const jsonElement = JSON.stringify(React.createElement('div'))
expect(React.isValidElement(JSON.parse(jsonElement))).toBe(false)

The reason is that the normal value of $$typeof is of type Symbol. Therefore, when ReactElement is JSON.stringify-ed, this property gets removed. In React.isValidElement, it checks whether $$typeof is equal to REACT_ELEMENT_TYPE, resulting in false as the output. However, in big-react-wasm, REACT_ELEMENT_TYPE is a string, so the result is true.

Why not change it to Symbol then? Well, Rust has many restrictions in place to ensure thread safety, making it cumbersome to define a constant of type Symbol. Let me provide an example given by ChatGPT to illustrate this:

use wasm_bindgen::prelude::*;
use js_sys::Symbol;
use std::sync::Mutex;

pub static REACT_ELEMENT_TYPE: Mutex<Option<Symbol>> = Mutex::new(None);

// Somewhere in your initialization code, you would set the symbol:
fn initialize() {
    let mut symbol = REACT_ELEMENT_TYPE.lock().unwrap();
    *symbol = Some(Symbol::for_("react.element"));
}

// And when you need to use the symbol, you would lock the Mutex to safely access it:
fn use_symbol() {
    let symbol = REACT_ELEMENT_TYPE.lock().unwrap();
    if let Some(ref symbol) = *symbol {
        // Use the symbol here
    }
}

  • Object without a prototype

The following test case creates an object without a prototype using Object.create. In JavaScript, it is possible to iterate over the keys of this object.

However, when calling config.dyn_ref::<Object>() to convert it to an Object in Rust, it returns None. But when calling config.is_object(), the result is indeed true.

it('does not fail if config has no prototype', () => {
  const config = Object.create(null, {foo: {value: 1, enumerable: true}})
  const element = React.createElement(ComponentFC, config)
  console.log(element)
  expect(element.props.foo).toBe(1)
})

So, for this situation, we can simply use the original config as the props:

Reflect::set(&react_element, &"props".into(), &config).expect("props panic");
  • react-dom Host Config

In the original implementation of react-dom's HostConfig, an error occurs if the window object does not exist:

fn create_text_instance(&self, content: String) -> Rc<dyn Any> {
    let window = window().expect("no global `window` exists");
    let document = window.document().expect("should have a document on window");
    Rc::new(Node::from(document.create_text_node(content.as_str())))
}

So, we need to make some modifications:

fn create_text_instance(&self, content: String) -> Rc<dyn Any> {
    match window() {
        None => {
            log!("no global `window` exists");
            Rc::new(())
        }
        Some(window) => {
            let document = window.document().expect("should have a document on window");
            Rc::new(Node::from(document.create_text_node(content.as_str())))
        }
    }
}

But wait, why doesn't big-react throw an error? It's because big-react specifies the testing environment as jsdom. According to the official documentation, jsdom is a pure JavaScript implementation of the web standards, specifically designed for Node.js, including the WHATWG DOM and HTML standards.

module.exports = {
  testEnvironment: 'jsdom',
}

If that's the case, why doesn't big-react-wasm work in the same jsdom environment? After studying the source code, I found that when window() is called, it actually executes the following code:

js_sys::global().dyn_into::<Window>().ok()

In the code snippet, when dyn_into::<Window>() is called, it uses instanceof to check if the current object is a Window. Could this be the reason? Let's experiment by adding a code snippet like this to the test cases:

console.log(window instanceof Window)

The result is false, surprisingly. It seems to be a bug in jsdom. Let's search on GitHub and indeed, we found an issue related to this. Moreover, someone has already provided a solution:

// jest-config.js
module.exports = {
  setupFilesAfterEnv: ['<rootDir>/setup-jest.js'],
}

// setup-jest.js
Object.setPrototypeOf(window, Window.prototype)

Let's add that solution and revert the Host Config back to its original state.

With these changes, all 17 test cases pass successfully.

Image description

Please kindly give me a star!

...



📌 Implement React v18 from Scratch Using WASM and Rust - [9] Unit Test with Jest


📈 120.85 Punkte

📌 Implement React v18 from Scratch Using WASM and Rust [16] Implement React Noop


📈 105.94 Punkte

📌 Implement React v18 from Scratch Using WASM and Rust - [13] Implement Lane and Batch Update


📈 99.81 Punkte

📌 Implement React v18 from Scratch Using WASM and Rust - [10] Implement Update for Single Node.


📈 98.28 Punkte

📌 Implement React v18 from Scratch Using WASM and Rust - [11] Implement Event System


📈 98.28 Punkte

📌 Implement React v18 from Scratch Using WASM and Rust - [12] Implement Update for Multi Node


📈 98.28 Punkte

📌 Implement React v18 from Scratch Using WASM and Rust - [14] Implement Scheduler


📈 98.28 Punkte

📌 Implement React v18 from Scratch Using WASM and Rust - [1] Build the Project


📈 85.86 Punkte

📌 Implement React v18 from Scratch Using WASM and Rust - [3] Reconciler & Renderer Design


📈 85.86 Punkte

📌 Implement React v18 from Scratch Using WASM and Rust - [4] Implementation of Begin Work Phase of Render Process


📈 85.86 Punkte

📌 Implement React v18 from Scratch Using WASM and Rust - [5] Implementation of Complete Work Phase of Render Process


📈 85.86 Punkte

📌 Implement React v18 from Scratch Using WASM and Rust - [6] Implementation of Commit Process


📈 85.86 Punkte

📌 Implement React v18 from Scratch Using WASM and Rust - [7] Support FunctionComponent Type


📈 85.86 Punkte

📌 Implement React v18 from Scratch Using WASM and Rust - [8] Support Hooks


📈 85.86 Punkte

📌 Simplifying jest stubs using jest-when


📈 43.6 Punkte

📌 Unit tests in React with Jest and Testing Library


📈 40.83 Punkte

📌 45sec scratch game vs 1min scratch game vs 10min scratch game


📈 39.21 Punkte

📌 Implement a Simple Calculator Android App by Reusing Logics in Rust via JavaScript-WASM Interfacing


📈 39.15 Punkte

📌 Effortless Testing Setup for React with Vite, TypeScript, Jest, and React Testing Library


📈 36.33 Punkte

📌 Running Unit Tests with MongoDB in a Node.js Express Application using Jest


📈 36.26 Punkte

📌 Vuln: radare2 '/format/wasm/wasm.c' Heap Buffer Overflow Vulnerability


📈 35.9 Punkte

📌 radare2 WASM File wasm.c wasm_dis() Pufferüberlauf


📈 35.9 Punkte

📌 radare2 WASM File wasm.c wasm_dis() memory corruption


📈 35.9 Punkte

📌 Binaryen 1.38.22 wasm/wasm-binary.cpp processFunctions() denial of service


📈 35.9 Punkte

📌 Binaryen 1.38.22 wasm/wasm-binary.cpp processFunctions() memory corruption


📈 35.9 Punkte

📌 Binaryen 1.38.22 wasm/wasm.cpp getFunctionOrNull denial of service


📈 35.9 Punkte

📌 Binaryen 1.38.22 WASM File wasm-binary.cpp getType() denial of service


📈 35.9 Punkte

📌 CVE-2023-27114 | radare2 5.8.3 p/wasm/wasm.c wasm_dis memory corruption (ID 21363)


📈 35.9 Punkte

📌 Rust WebAssembly (wasm) on Arch Linux with Webpack (Rust 1.66)


📈 35.49 Punkte

📌 Utilização e Benefícios do Rerender em Testes de Componentes React com Jest e React Testing Library


📈 34.81 Punkte

📌 Virtual Scrolling in React: Implementation from scratch and using react-window


📈 34.52 Punkte

📌 Beginner Guide on Unit Testing in React using React Testing Library and Vitest


📈 33.6 Punkte

📌 Applying Unit Tests on NestJS with Jest and GitHub Actions


📈 33.18 Punkte

📌 Unit Testing in Node.js and TypeScript: A Comprehensive Guide with Jest Integration


📈 33.18 Punkte

📌 How to Implement Face Detection in React Native Using React Native Vision Camera


📈 32.35 Punkte











matomo