projectRoot
├── src
│ ├── file1.js
│ └── file2.js
├── built
└── tsconfig.jsonjson{ "compilerOptions": { "outDir": "./built", "allowJs": true, "target": "es5" }, "include": ["./src/**/*"]}shellnpm install ts-loader source-map-loaderjsmodule.exports = { entry: "./src/index.ts", output: { filename: "./dist/bundle.js", }, // Enable sourcemaps for debugging webpack's output. devtool: "source-map", resolve: { // Add '.ts' and '.tsx' as resolvable extensions. extensions: ["", ".webpack.js", ".web.js", ".ts", ".tsx", ".js"], }, module: { rules: [ // All files with a '.ts' or '.tsx' extension will be handled by 'ts-loader'. { test: /\.tsx?$/, loader: "ts-loader" }, // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'. { test: /\.js$/, loader: "source-map-loader" }, ], }, // Other options...};ts// For Node/CommonJSdeclare function require(path: string): any;ts// For RequireJS/AMDdeclare function define(...args: any[]): any;jsvar foo = require("foo");foo.doStuff();jsdefine(["foo"], function (foo) { foo.doStuff();});tsimport foo = require("foo");foo.doStuff();shellnpm install -S @types/lodashjsmodule.exports.feedPets = function (pets) { // ...};tsexport function feedPets(pets) { // ...}jsvar express = require("express");var app = express();jsfunction foo() { // ...}module.exports = foo;tsfunction foo() { // ...}export = foo;jsfunction myCoolFunction() { if (arguments.length == 2 && !Array.isArray(arguments[1])) { var f = arguments[0]; var arr = arguments[1]; // ... } // ...}myCoolFunction( function (x) { console.log(x); }, [1, 2, 3, 4]);myCoolFunction( function (x) { console.log(x); }, 1, 2, 3, 4);tsfunction myCoolFunction(f: (x: number) => void, nums: number[]): void;function myCoolFunction(f: (x: number) => void, ...nums: number[]): void;function myCoolFunction() { if (arguments.length == 2 && !Array.isArray(arguments[1])) { var f = arguments[0]; var arr = arguments[1]; // ... } // ...}jsvar options = {};options.color = "red";options.volume = 11;tslet options = { color: "red", volume: 11,};tsinterface Options { color: string; volume: number;}let options = {} as Options;options.color = "red";options.volume = 11;tsdeclare var foo: string[] | null;foo.length; // error - 'foo' is possibly 'null'foo!.length; // okay - 'foo!' just has type 'string[]'tsclass Point { constructor(public x, public y) {} getDistance(p: Point) { let dx = p.x - this.x; let dy = p.y - this.y; return Math.sqrt(dx ** 2 + dy ** 2); }}// ...// Reopen the interface.interface Point { distanceFromOrigin(): number;}Point.prototype.distanceFromOrigin = function () { return this.getDistance({ x: 0, y: 0 });};tsPoint.prototype.distanceFromOrigin = function (this: Point) { return this.getDistance({ x: 0, y: 0 });};

ReactDOM.createPortal(child, container)render() {
// React mounts a new div and renders the children into it
return (
<div> {this.props.children}
</div> );
}render() {
// React does *not* create a new div. It renders the children into `domNode`.
// `domNode` is any valid DOM node, regardless of its location in the DOM.
return ReactDOM.createPortal(
this.props.children,
domNode );
}<html>
<body>
<div id="app-root"></div>
<div id="modal-root"></div>
</body>
</html>// These two containers are siblings in the DOM
const appRoot = document.getElementById('app-root');
const modalRoot = document.getElementById('modal-root');
class Modal extends React.Component {
constructor(props) {
super(props);
this.el = document.createElement('div');
}
componentDidMount() {
// The portal element is inserted in the DOM tree after
// the Modal's children are mounted, meaning that children
// will be mounted on a detached DOM node. If a child
// component requires to be attached to the DOM tree
// immediately when mounted, for example to measure a
// DOM node, or uses 'autoFocus' in a descendant, add
// state to Modal and only render the children when Modal
// is inserted in the DOM tree.
modalRoot.appendChild(this.el);
}
componentWillUnmount() {
modalRoot.removeChild(this.el);
}
render() {
return ReactDOM.createPortal( this.props.children, this.el ); }
}
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {clicks: 0};
this.handleClick = this.handleClick.bind(this);
}
handleClick() { // This will fire when the button in Child is clicked, // updating Parent's state, even though button // is not direct descendant in the DOM. this.setState(state => ({ clicks: state.clicks + 1 })); }
render() {
return (
<div onClick={this.handleClick}> <p>Number of clicks: {this.state.clicks}</p>
<p>
Open up the browser DevTools
to observe that the button
is not a child of the div
with the onClick handler.
</p>
<Modal> <Child /> </Modal> </div>
);
}
}
function Child() {
// The click event on this button will bubble up to parent, // because there is no 'onClick' attribute defined return (
<div className="modal">
<button>Click</button> </div>
);
}
ReactDOM.render(<Parent />, appRoot);import * as React from 'react';
import { createPortal } from 'react-dom';
const Portal = ({ children }: React.PropsWithChildren<{}>) => {
const portalNode = typeof window !== 'undefined' && document.querySelector('#root');
if (!portalNode) {
return null;
}
return createPortal(children, portalNode);
};
export { Portal };meeting with james
container](https: //testing-library.com/docs/react-testing-library/api/#container)const {/* */} = render(Component) returns:function render( ui: React.ReactElement<any>, options?: { /* You won't often use this, expand below for docs on options */ },): RenderResultimport {render} from '@testing-library/react'render(<div />)import {render} from '@testing-library/react'import '@testing-library/jest-dom'test('renders a message', () => {
const {container, getByText} = render(<Greeting />) expect(getByText('Hello, world!')).toBeInTheDocument() expectconst table = document.createElement("table");
const { container } = render(<TableBody {...props} />, {
container: document.body.appendChild(table),
});// Example, a function to traverse table contentsimport * as tableQueries from 'my-table-query-library'import {queries} from '@testing-library/react'
const { getByRowColumn, getByText } = render(<MyTable />, {
queries: { ...queries, ...tableQueries },
});const { getByLabelText, queryAllByTestId } = render(<Component />);import React from 'react'import {render} from '@testing-library/react'
const HelloWorld = () => <h1>Hello World</h1>
const {debug} = render(<HelloWorld />)debug()
// <div>
// <h1>Hello World</h1>
// </div>
// you can also pass an element: debug(getByTestId('messages'))
// and you can pass all the same arguments to debug as you can
// to prettyDOM:
//
const maxLengthToPrint = 10000
// debug(getByTestId('messages'), maxLengthToPrint, {highlight: false})import { render } from "@testing-library/react";
const { rerender } = render(<NumberDisplay number={1} />);
// re-render the same component with different propsrerender(<NumberDisplay number={2} />)import {render} from '@testing-library/react'
const {container, unmount} = render(<Login />)unmount()
// your component has been unmounted and now: container.innerHTML === ''import React, {useState} from 'react'import {render, fireEvent} from '@testing-library/react'
const TestComponent = () => {
const [count, setCounter] = useState(0) return ( <button onClick={()
const {getByText, asFragment} = render(<TestComponent />)
const firstRender = asFragment()fireEvent.click(getByText(/Click to increase/))
// This will snapshot only the difference between the first render, and the
// state of the DOM after the click event.
// See https:
//github.com/jest-community/snapshot-diffexpect(firstRender).toMatchDiffSnapshot(asFragment())import {cleanup, render} from '@testing-library/react'import test from 'ava'test.afterEach(cleanup)test('renders into document', () => { render(<div />)
// ...})
// ... more tests ...import {render, fireEvent, screen} from
jest.mock('src/lib/useIntersection');renderWithCTX(<Accordion {...props} />);
screen.logTestingPlaygroundURL();import { screen, fireEvent } from "@testing-library/react";
import { renderWithCTX } from "src/lib/testWrappers";
import { compositionFunction } from "./composition";
import data from "./data";
import Accordion from "./index";
import "@testing-library/jest-dom";
jest.mock("src/lib/useIntersection");
describe("Accordion", () => {
const props = compositionFunction(data);
it("render the correct items", () => {
renderWithCTX(<Accordion {...props} />);
screen.logTestingPlaygroundURL();
const text = screen.getByText();
for (let i = 0; i < props.items.length - 1; i++)
//
const accordionItemsText = screen.getAllByRole("listitem");
//
// expect(numItems.length).toBe(data.fields.items.length);
// expect(accordionItemsText[0]).toHaveTextContent(props?.items[0]?.text?.value as string);
// typescript needs the value passed in to be a string
});
it("should render Accordion Component with image", () => {
// look up memory router...
renderWithCTX(<Accordion {...props} />);
const img = screen.getByRole("img", { name: /facebook/i });
expect(img).toBeInTheDocument();
});
it("fires the click handler on click", () => {
renderWithCTX(<Accordion {...props} />);
const buttons = screen.getAllByRole("button");
for (let i = 0; i < buttons.length - 1; i++) {
const curButton = buttons[i];
fireEvent.click(curButton);
}
});
it("changes the background color if theme prop is changed", () => {
renderWithCTX(<Accordion {...props} />);
const list = screen.getByRole("list");
expect(list).toHaveClass(themeMap.footer.button);
});
});