@multiplatform.one/config 7.4.0 → 7.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/oxlint.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ export const COLOR_LITERAL: RegExp;
2
+ export const PALETTE_FILE: RegExp;
3
+ export const CHROME_PROPS: readonly string[];
4
+ export const LAYOUT_PROPS: readonly string[];
5
+ export function isPaletteModule(filename: string | undefined): boolean;
6
+ export function matchColorLiteral(value: unknown): string | undefined;
7
+ export const plugin: {
8
+ meta?: { name?: string };
9
+ rules?: Record<string, unknown>;
10
+ };
11
+ declare const defaultExport: typeof plugin;
12
+ export default defaultExport;
package/oxlint.mjs ADDED
@@ -0,0 +1,183 @@
1
+ /**
2
+ * Oxlint JS plugin — multiplatform.one convention rules.
3
+ *
4
+ * Consuming apps enable it with one config line:
5
+ *
6
+ * { "jsPlugins": ["@multiplatform.one/config/oxlint"] }
7
+ *
8
+ * Rules:
9
+ * mpo-conventions/no-hex-literals — ban #rgb/#rrggbb(/aa) and rgb()/hsl()
10
+ * string literals. Palette modules (themes/base, themes/accent, and
11
+ * files whose name contains "palette") are exempt: a 12-step ramp is
12
+ * the deliverable.
13
+ * mpo-conventions/no-raw-typography — AN-8: app text never rides raw
14
+ * Tamagui*-prefixed typography escape hatches (TamaguiText, TamaguiHeading,
15
+ * TamaguiH1…, TamaguiParagraph, TamaguiSizableText, TamaguiAnchor) outside
16
+ * public/. House Text/Heading shadows are the bare names (MPO-20).
17
+ *
18
+ * MPO-17 (no-chrome-props / no-raw-geometry) will add rules to this same
19
+ * plugin. The chrome/layout vocabularies below are the export surface those
20
+ * rules will use; they are not enforced yet.
21
+ */
22
+
23
+ /** Hex + functional CSS colour literals. AST-visited only (not a text scan). */
24
+ export const COLOR_LITERAL =
25
+ /#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})\b|(?:rgba?|hsla?)\([^)]*\)/i;
26
+
27
+ /** Palette modules where a 12-step ramp in hex/hsl is the deliverable (EN-2). */
28
+ export const PALETTE_FILE =
29
+ /(?:^|\/)themes\/(base|accent)\.(tsx?|jsx?)$|(?:^|\/)[^/]*palette[^/]*\.(tsx?|jsx?)$/i;
30
+
31
+ const RAW_TYPOGRAPHY_HATCH = /^Tamagui(?:Text|SizableText|Paragraph|Heading|H[1-6]|Anchor)$/;
32
+
33
+ /**
34
+ * Chrome props MPO-17 `no-chrome-props` will ban on imported
35
+ * `@multiplatform.one/*` components (including Tamagui shorthands).
36
+ * Layout composition through `{...props}` stays legal.
37
+ */
38
+ export const CHROME_PROPS = Object.freeze([
39
+ "backgroundColor",
40
+ "bg",
41
+ "borderColor",
42
+ "bc",
43
+ "borderWidth",
44
+ "bw",
45
+ "borderRadius",
46
+ "br",
47
+ "shadowColor",
48
+ "shadowOffset",
49
+ "shadowOpacity",
50
+ "shadowRadius",
51
+ "elevation",
52
+ "fontFamily",
53
+ "ff",
54
+ "fontWeight",
55
+ "fow",
56
+ "color",
57
+ ]);
58
+
59
+ /**
60
+ * Layout props callers may pass through the sanctioned `{...props}` hatch.
61
+ * Sibling margins are layout; chrome (background, radius, type) is not.
62
+ */
63
+ export const LAYOUT_PROPS = Object.freeze([
64
+ "flex",
65
+ "flexBasis",
66
+ "flexGrow",
67
+ "flexShrink",
68
+ "alignSelf",
69
+ "alignItems",
70
+ "justifyContent",
71
+ "position",
72
+ "zIndex",
73
+ "margin",
74
+ "marginTop",
75
+ "marginRight",
76
+ "marginBottom",
77
+ "marginLeft",
78
+ "marginHorizontal",
79
+ "marginVertical",
80
+ ]);
81
+
82
+ /**
83
+ * @param {string | undefined} filename
84
+ * @returns {boolean}
85
+ */
86
+ export function isPaletteModule(filename) {
87
+ if (!filename) return false;
88
+ const normalized = filename.replaceAll("\\", "/");
89
+ return PALETTE_FILE.test(normalized);
90
+ }
91
+
92
+ /**
93
+ * @param {unknown} value
94
+ * @returns {string | undefined} the matched literal, if any
95
+ */
96
+ export function matchColorLiteral(value) {
97
+ if (typeof value !== "string") return undefined;
98
+ const match = value.match(COLOR_LITERAL);
99
+ return match?.[0];
100
+ }
101
+
102
+ /** @type {import("eslint").ESLint.Plugin} */
103
+ export const plugin = {
104
+ meta: {
105
+ name: "mpo-conventions",
106
+ },
107
+ rules: {
108
+ "no-hex-literals": {
109
+ meta: {
110
+ type: "problem",
111
+ docs: {
112
+ description:
113
+ "Disallow hex / rgb / hsl color literals; use theme tokens / knob recipes instead.",
114
+ },
115
+ schema: [],
116
+ messages: {
117
+ hex: "Color literal {{value}} is banned. Use theme tokens (e.g. $color10) or semantic ramps.",
118
+ },
119
+ },
120
+ create(context) {
121
+ const filename = context.filename ?? context.getFilename?.() ?? "";
122
+ if (isPaletteModule(filename)) {
123
+ return {};
124
+ }
125
+
126
+ function reportIfColor(node, value) {
127
+ const matched = matchColorLiteral(value);
128
+ if (!matched) return;
129
+ context.report({
130
+ node,
131
+ messageId: "hex",
132
+ data: { value: matched },
133
+ });
134
+ }
135
+
136
+ return {
137
+ Literal(node) {
138
+ if (typeof node.value === "string") {
139
+ reportIfColor(node, node.value);
140
+ }
141
+ },
142
+ TemplateElement(node) {
143
+ reportIfColor(node, node.value?.cooked ?? "");
144
+ },
145
+ };
146
+ },
147
+ },
148
+ "no-raw-typography": {
149
+ meta: {
150
+ type: "problem",
151
+ docs: {
152
+ description:
153
+ "AN-8: never render app text through raw typography. Use the house Text/SizableText/Paragraph/Anchor and Heading/H1-H6 (the bare @multiplatform.one/components names), which carry the typography knobs on every platform.",
154
+ },
155
+ schema: [],
156
+ messages: {
157
+ rawTypography:
158
+ "{{name}} is a raw typography escape hatch — knob-dead on every platform (AN-8). Import the bare house name from @multiplatform.one/components instead.",
159
+ },
160
+ },
161
+ create(context) {
162
+ return {
163
+ ImportDeclaration(node) {
164
+ if (node.source?.value !== "@multiplatform.one/components") return;
165
+ for (const specifier of node.specifiers ?? []) {
166
+ if (specifier.type !== "ImportSpecifier") continue;
167
+ const imported = specifier.imported?.name ?? specifier.imported?.value;
168
+ if (typeof imported === "string" && RAW_TYPOGRAPHY_HATCH.test(imported)) {
169
+ context.report({
170
+ node: specifier,
171
+ messageId: "rawTypography",
172
+ data: { name: imported },
173
+ });
174
+ }
175
+ }
176
+ },
177
+ };
178
+ },
179
+ },
180
+ },
181
+ };
182
+
183
+ export default plugin;
package/package.json CHANGED
@@ -1,10 +1,12 @@
1
1
  {
2
2
  "name": "@multiplatform.one/config",
3
- "version": "7.4.0",
3
+ "version": "7.5.0",
4
4
  "description": "Shared build and test configuration presets for multiplatform.one",
5
5
  "keywords": [
6
6
  "config",
7
+ "lint",
7
8
  "multiplatform.one",
9
+ "oxlint",
8
10
  "playwright",
9
11
  "storybook",
10
12
  "tsconfig",
@@ -27,8 +29,13 @@
27
29
  "files": [
28
30
  "src",
29
31
  "lib",
32
+ "pin-react-require.cjs",
30
33
  "tsconfig",
31
34
  "README.md",
35
+ "oxlint.mjs",
36
+ "oxlint.d.ts",
37
+ "lint.mjs",
38
+ "lint.d.ts",
32
39
  "!tsconfig/dist",
33
40
  "!tsconfig/types",
34
41
  "types",
@@ -74,7 +81,13 @@
74
81
  "./tsconfig/base.json": "./tsconfig/base.json",
75
82
  "./tsconfig/build.json": "./tsconfig/build.json",
76
83
  "./tsconfig/app.json": "./tsconfig/app.json",
77
- "./react-native-config": "./src/react-native.config.cjs"
84
+ "./react-native-config": "./src/react-native.config.cjs",
85
+ "./oxlint": "./oxlint.mjs",
86
+ "./lint": {
87
+ "types": "./lint.d.ts",
88
+ "default": "./lint.mjs",
89
+ "import": "./lint.mjs"
90
+ }
78
91
  },
79
92
  "publishConfig": {
80
93
  "access": "public"
@@ -87,7 +100,7 @@
87
100
  "vite-plugin-external": "^6.2.2",
88
101
  "vite-plugin-i18next-loader": "^3.1.3",
89
102
  "vitest": "^4.1.5",
90
- "@multiplatform.one/utils": "7.4.0"
103
+ "@multiplatform.one/utils": "7.5.0"
91
104
  },
92
105
  "devDependencies": {
93
106
  "tsdown": "^0.21.10",
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Vitest workers `require()` CJS deps (use-sync-external-store) without
5
+ * going through Vite aliases. The factory in vitest.ts sets MPO_VITEST_*
6
+ * to the same physical copies the aliases bind; this setup file (prepended
7
+ * onto every createVitestConfig setupFiles list) makes those requires land
8
+ * there. See MPO-37.
9
+ */
10
+ const Module = require("module");
11
+ const path = require("path");
12
+
13
+ const reactDir = process.env.MPO_VITEST_REACT;
14
+ const reactDomDir = process.env.MPO_VITEST_REACT_DOM;
15
+ const schedulerDir = process.env.MPO_VITEST_SCHEDULER;
16
+
17
+ if (reactDir && reactDomDir && !Module._mpoOneReact) {
18
+ Module._mpoOneReact = true;
19
+ const orig = Module._resolveFilename;
20
+ Module._resolveFilename = function pinned(request, parent, isMain, options) {
21
+ const next =
22
+ request === "react"
23
+ ? reactDir
24
+ : request.startsWith("react/")
25
+ ? path.join(reactDir, request.slice("react/".length))
26
+ : request === "react-dom"
27
+ ? reactDomDir
28
+ : request.startsWith("react-dom/")
29
+ ? path.join(reactDomDir, request.slice("react-dom/".length))
30
+ : request === "scheduler" && schedulerDir
31
+ ? schedulerDir
32
+ : null;
33
+ if (next) {
34
+ try {
35
+ return orig.call(this, next, parent, isMain, options);
36
+ } catch {
37
+ // package layout didn't match — keep Node's original lookup
38
+ }
39
+ }
40
+ return orig.call(this, request, parent, isMain, options);
41
+ };
42
+ }
@@ -0,0 +1,52 @@
1
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
2
+ import { tmpdir } from "node:os";
3
+ import { join } from "node:path";
4
+ import { afterEach, describe, expect, it, vi } from "vitest";
5
+ import { resolveRoots, runConventionChecks } from "../lint.mjs";
6
+
7
+ const fixtures: string[] = [];
8
+
9
+ afterEach(() => {
10
+ for (const dir of fixtures.splice(0)) {
11
+ rmSync(dir, { recursive: true, force: true });
12
+ }
13
+ });
14
+
15
+ function makeTree() {
16
+ const root = mkdtempSync(join(tmpdir(), "mpo-lint-"));
17
+ fixtures.push(root);
18
+ mkdirSync(join(root, "apps", "demo"), { recursive: true });
19
+ mkdirSync(join(root, "features", "demo"), { recursive: true });
20
+ writeFileSync(join(root, "apps", "demo", "App.tsx"), "export const App = () => null;\n");
21
+ return root;
22
+ }
23
+
24
+ describe("resolveRoots", () => {
25
+ it("defaults apps/features/public under root", () => {
26
+ const roots = resolveRoots({ root: "/tmp/app" });
27
+ expect(roots.apps).toBe(join("/tmp/app", "apps"));
28
+ expect(roots.features).toBe(join("/tmp/app", "features"));
29
+ expect(roots.public).toBe(join("/tmp/app", "public"));
30
+ });
31
+ });
32
+
33
+ describe("runConventionChecks", () => {
34
+ it("fails on a .css file under apps/", () => {
35
+ const root = makeTree();
36
+ writeFileSync(join(root, "apps", "demo", "bad.css"), "body { color: red; }\n");
37
+ const error = vi.spyOn(console, "error").mockImplementation(() => {});
38
+ const code = runConventionChecks({ roots: { root } });
39
+ error.mockRestore();
40
+ expect(code).toBe(1);
41
+ });
42
+
43
+ it("passes a product app with a features twin and no css", () => {
44
+ const root = makeTree();
45
+ const log = vi.spyOn(console, "log").mockImplementation(() => {});
46
+ const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
47
+ const code = runConventionChecks({ roots: { root } });
48
+ log.mockRestore();
49
+ warn.mockRestore();
50
+ expect(code).toBe(0);
51
+ });
52
+ });
@@ -0,0 +1,61 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { dirname, join } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { describe, expect, it } from "vitest";
5
+ import {
6
+ CHROME_PROPS,
7
+ LAYOUT_PROPS,
8
+ isPaletteModule,
9
+ matchColorLiteral,
10
+ plugin,
11
+ } from "../oxlint.mjs";
12
+
13
+ const pkg = JSON.parse(
14
+ readFileSync(join(dirname(fileURLToPath(import.meta.url)), "..", "package.json"), "utf8"),
15
+ ) as {
16
+ exports: Record<string, string | { import?: string; default?: string; types?: string }>;
17
+ files: string[];
18
+ };
19
+
20
+ describe("package exports", () => {
21
+ it("exports ./oxlint and ./lint and lists both in files", () => {
22
+ expect(pkg.exports["./oxlint"]).toBe("./oxlint.mjs");
23
+ const lintExport = pkg.exports["./lint"];
24
+ const lintPath = typeof lintExport === "string" ? lintExport : lintExport?.import;
25
+ expect(lintPath).toBe("./lint.mjs");
26
+ expect(pkg.files).toContain("oxlint.mjs");
27
+ expect(pkg.files).toContain("lint.mjs");
28
+ });
29
+ });
30
+
31
+ describe("matchColorLiteral", () => {
32
+ it("matches hex and functional CSS colours, not a Pokedex number in isolation of AST", () => {
33
+ expect(matchColorLiteral("#34c759")).toBe("#34c759");
34
+ expect(matchColorLiteral("#fff")).toBe("#fff");
35
+ expect(matchColorLiteral("rgba(0,0,0,0.35)")).toBe("rgba(0,0,0,0.35)");
36
+ expect(matchColorLiteral("hsl(0, 0%, 50%)")).toBe("hsl(0, 0%, 50%)");
37
+ expect(matchColorLiteral("$color10")).toBeUndefined();
38
+ expect(matchColorLiteral("#025")).toBe("#025");
39
+ });
40
+ });
41
+
42
+ describe("isPaletteModule", () => {
43
+ it("exempts themes/base, themes/accent, and *palette* files", () => {
44
+ expect(isPaletteModule("packages/themes/base.ts")).toBe(true);
45
+ expect(isPaletteModule("packages/themes/accent.ts")).toBe(true);
46
+ expect(isPaletteModule("src/brand-palette.ts")).toBe(true);
47
+ expect(isPaletteModule("features/console/src/conditions/ConditionsIndicator.tsx")).toBe(false);
48
+ });
49
+ });
50
+
51
+ describe("MPO-17 export surface", () => {
52
+ it("exposes chrome vs layout vocabularies and the oxlint plugin", () => {
53
+ expect(CHROME_PROPS).toContain("backgroundColor");
54
+ expect(CHROME_PROPS).toContain("bg");
55
+ expect(LAYOUT_PROPS).toContain("flex");
56
+ expect(plugin.meta?.name).toBe("mpo-conventions");
57
+ expect(plugin.rules?.["no-hex-literals"]).toBeDefined();
58
+ expect(plugin.rules?.["no-raw-typography"]).toBeDefined();
59
+ expect(plugin.rules?.["no-chrome-props"]).toBeUndefined();
60
+ });
61
+ });
@@ -0,0 +1,151 @@
1
+ /**
2
+ * createVitestConfig — resolve.extensions must never prefer a .test.* sibling,
3
+ * and dedupeReact aliases must bind one physical React (MPO-11 / MPO-37).
4
+ *
5
+ * Regression guard for MPO-11: the defaults listed ".test.ts" / ".test.tsx"
6
+ * first, so vite resolved an extensionless `import "./foo"` to foo.test.ts
7
+ * whenever both files existed. That pulled the test file's own imports into the
8
+ * module graph and killed the lookout unit job with "Cannot bundle Node.js
9
+ * built-in node:test imported from src/format.test.ts".
10
+ *
11
+ * Regression guard for MPO-37: aliasing react at the hoisted root directory
12
+ * while Vite realpath'd a package-local symlink put two copies in one graph.
13
+ * Render specs then died on `Cannot read properties of null (reading 'useEffect')`.
14
+ */
15
+
16
+ import fs from "node:fs";
17
+ import path from "node:path";
18
+ import { fileURLToPath } from "node:url";
19
+ import { afterAll, describe, expect, it, vi } from "vitest";
20
+ import { createServer, type ViteDevServer } from "vite";
21
+ import { createVitestConfig } from "./vitest.js";
22
+
23
+ const fixtureDir = path.resolve(
24
+ path.dirname(fileURLToPath(import.meta.url)),
25
+ "../tests/fixtures/extensionless-resolve",
26
+ );
27
+
28
+ const servers: ViteDevServer[] = [];
29
+
30
+ afterAll(async () => {
31
+ await Promise.all(servers.map((server) => server.close()));
32
+ });
33
+
34
+ /**
35
+ * Resolve a specifier through a real vite pipeline built from the produced
36
+ * config, so the assertion exercises vite's own extension probing rather than
37
+ * re-implementing it.
38
+ */
39
+ async function resolveThroughVite(specifier: string, importer: string) {
40
+ const config = createVitestConfig({ tamaguiConfig: false, dedupeReact: false });
41
+ const server = await createServer({
42
+ configFile: false,
43
+ logLevel: "silent",
44
+ root: fixtureDir,
45
+ server: { middlewareMode: true },
46
+ resolve: config.resolve,
47
+ });
48
+ servers.push(server);
49
+ const environment = server.environments?.client ?? server.environments?.ssr;
50
+ const container = environment ? environment.pluginContainer : (server as any).pluginContainer;
51
+ const resolved = await container.resolveId(specifier, importer);
52
+ return resolved?.id ?? null;
53
+ }
54
+
55
+ describe("resolve.extensions", () => {
56
+ it("does not list any .test.* extension", () => {
57
+ const extensions = createVitestConfig().resolve?.extensions ?? [];
58
+ expect(extensions.filter((extension) => extension.startsWith(".test."))).toEqual([]);
59
+ });
60
+
61
+ it("still resolves platform-specific and plain source extensions, web first", () => {
62
+ const extensions = createVitestConfig().resolve?.extensions ?? [];
63
+ expect(extensions).toEqual([
64
+ ".web.ts",
65
+ ".web.tsx",
66
+ ".web.js",
67
+ ".web.jsx",
68
+ ".ts",
69
+ ".tsx",
70
+ ".js",
71
+ ".jsx",
72
+ ]);
73
+ expect(extensions.indexOf(".web.ts")).toBeLessThan(extensions.indexOf(".ts"));
74
+ });
75
+
76
+ it("resolves an extensionless ./foo to foo.ts even when foo.test.ts sits beside it", async () => {
77
+ const id = await resolveThroughVite("./foo", path.join(fixtureDir, "entry.ts"));
78
+ expect(id).toBeTruthy();
79
+ expect(path.basename(id!)).toBe("foo.ts");
80
+ expect(id).not.toContain(".test.");
81
+ });
82
+ });
83
+
84
+ describe("dedupeReact aliases", () => {
85
+ const configDir = path.dirname(fileURLToPath(import.meta.url));
86
+ const componentsDir = path.resolve(configDir, "../../components");
87
+ const componentsReact = path.join(componentsDir, "node_modules/react");
88
+ const componentsReactDom = path.join(componentsDir, "node_modules/react-dom");
89
+
90
+ function aliasMap() {
91
+ return createVitestConfig({ tamaguiConfig: false }).resolve?.alias as Record<string, string>;
92
+ }
93
+
94
+ it("binds react-dom/client and jsx-runtime to the same physical copies as the packages", () => {
95
+ const aliases = aliasMap();
96
+ expect(aliases["react-dom/client"]).toBe(path.join(aliases["react-dom"], "client"));
97
+ expect(aliases["react-dom/server"]).toBe(path.join(aliases["react-dom"], "server"));
98
+ expect(aliases["react/jsx-runtime"]).toBe(path.join(aliases.react, "jsx-runtime"));
99
+ expect(aliases["react/jsx-dev-runtime"]).toBe(path.join(aliases.react, "jsx-dev-runtime"));
100
+ expect(aliases.react).not.toBe(aliases["react-dom"]);
101
+ });
102
+
103
+ it("canonicalizes each alias through realpath so Vite cannot see two copies", () => {
104
+ const aliases = aliasMap();
105
+ for (const pkg of ["react", "react-dom", "scheduler"] as const) {
106
+ expect(fs.existsSync(aliases[pkg])).toBe(true);
107
+ expect(aliases[pkg]).toBe(fs.realpathSync(aliases[pkg]));
108
+ }
109
+ });
110
+
111
+ it.skipIf(!fs.existsSync(componentsReact) || !fs.existsSync(componentsReactDom))(
112
+ "prefers the package-under-test physical copy over the hoisted root",
113
+ () => {
114
+ const cwdSpy = vi.spyOn(process, "cwd").mockReturnValue(componentsDir);
115
+ try {
116
+ const aliases = aliasMap();
117
+ expect(aliases.react).toBe(fs.realpathSync(componentsReact));
118
+ expect(aliases["react-dom"]).toBe(fs.realpathSync(componentsReactDom));
119
+ } finally {
120
+ cwdSpy.mockRestore();
121
+ }
122
+ },
123
+ );
124
+
125
+ it("does not also dedupe react to the hoisted root copy", () => {
126
+ const dedupe = createVitestConfig({ tamaguiConfig: false }).resolve?.dedupe ?? [];
127
+ expect(dedupe).not.toContain("react");
128
+ expect(dedupe).not.toContain("react-dom");
129
+ });
130
+
131
+ it("inlines the CJS react deps that Node would otherwise require from the hoisted root", () => {
132
+ const config = createVitestConfig({ tamaguiConfig: false }) as {
133
+ test?: { server?: { deps?: { inline?: unknown[]; external?: unknown[] } } };
134
+ };
135
+ const inline = config.test?.server?.deps?.inline ?? [];
136
+ expect(
137
+ inline.some((entry) => entry instanceof RegExp && String(entry).includes("@tanstack")),
138
+ ).toBe(true);
139
+ expect(inline).toContain("use-sync-external-store");
140
+ });
141
+
142
+ it("installs a worker setup that pins CJS require('react') to the same copy", () => {
143
+ const config = createVitestConfig({ tamaguiConfig: false }) as {
144
+ test?: { setupFiles?: string[]; server?: { deps?: { external?: unknown[] } } };
145
+ };
146
+ const files = config.test?.setupFiles ?? [];
147
+ expect(files.some((file) => file.endsWith("pin-react-require.cjs"))).toBe(true);
148
+ const external = config.test?.server?.deps?.external ?? [];
149
+ expect(external.some((entry) => String(entry).endsWith("pin-react-require.cjs"))).toBe(true);
150
+ });
151
+ });