@elliemae/ds-monorepo-devops 3.70.0-next.49 → 3.70.0-next.51

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.
@@ -1,4 +1,5 @@
1
1
  /* eslint-disable max-len */
2
+ import fs from 'node:fs';
2
3
  import path from 'node:path';
3
4
  import { fileURLToPath } from 'node:url';
4
5
  import normalizePath from 'normalize-path';
@@ -19,6 +20,38 @@ const getNodeModulesPath = (fileName) => {
19
20
  );
20
21
  };
21
22
 
23
+ // styled-components@5.3.11 currently resolves to two different pnpm store instances (one paired
24
+ // with react-is@18.3.1, one with react-is@19.2.8 — see pnpm/pnpm#11834: dedupePeerDependents
25
+ // fails to collapse peer-cyclic packages like styled-components <-> babel-plugin-styled-components).
26
+ // @xstyled/styled-components (used by ds-system's styled() wrapper and themeProviderHOC for theme
27
+ // merging) inherits that split per-consumer. Two module instances means two separate Context
28
+ // objects, so ThemeProvider from one instance is invisible to styled() calls resolved through the
29
+ // other, which is what actually breaks theme merging (not react-is itself). This pins both
30
+ // packages to the single instance built against react-is@18.3.1. Resolved dynamically (not a
31
+ // hardcoded folder name) because the pnpm store path encodes @babel/core's version in its hash.
32
+ const resolvePinnedStyledComponentsPaths = () => {
33
+ const monorepoRoot = findMonoRepoRoot(process.cwd());
34
+ if (!monorepoRoot) return null;
35
+ const pnpmDir = path.join(monorepoRoot, 'node_modules', '.pnpm');
36
+ if (!fs.existsSync(pnpmDir)) return null;
37
+ const entries = fs.readdirSync(pnpmDir);
38
+ const scEntry = entries.find((e) => e.startsWith('styled-components@5.3.11') && e.includes('_react-is@18.3.1_'));
39
+ if (!scEntry) return null;
40
+ const styledComponentsPath = path.join(pnpmDir, scEntry, 'node_modules', 'styled-components');
41
+ const scRealPath = fs.realpathSync(styledComponentsPath);
42
+ const xscEntry = entries
43
+ .filter((e) => e.startsWith('@xstyled+styled-components@3.8.1'))
44
+ .find((e) => {
45
+ const nested = path.join(pnpmDir, e, 'node_modules', 'styled-components');
46
+ return fs.existsSync(nested) && fs.realpathSync(nested) === scRealPath;
47
+ });
48
+ if (!xscEntry) return null;
49
+ const xstyledStyledComponentsPath = path.join(pnpmDir, xscEntry, 'node_modules', '@xstyled', 'styled-components');
50
+ return { styledComponentsPath, xstyledStyledComponentsPath };
51
+ };
52
+
53
+ const pinnedStyledComponentsPaths = resolvePinnedStyledComponentsPaths();
54
+
22
55
  const configuredJestConfig = {
23
56
  coverageThreshold: {},
24
57
  coverageProvider: 'v8',
@@ -39,6 +72,13 @@ const configuredJestConfig = {
39
72
  '@elliemae/pui-diagnostics': getMockFilePath('pui-diagnostics.js'),
40
73
  'react-spring/web': getNodeModulesPath('react-spring/web.cjs.js'),
41
74
  'react-spring/renderprops': getNodeModulesPath('react-spring/renderprops.cjs.js'),
75
+ // See resolvePinnedStyledComponentsPaths above for why these two are needed.
76
+ ...(pinnedStyledComponentsPaths
77
+ ? {
78
+ '^styled-components$': normalizePath(pinnedStyledComponentsPaths.styledComponentsPath),
79
+ '^@xstyled/styled-components$': normalizePath(pinnedStyledComponentsPaths.xstyledStyledComponentsPath),
80
+ }
81
+ : {}),
42
82
  },
43
83
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
44
84
  setupFilesAfterEnv: [path.resolve(__dirname, './setup-tests.js'), path.resolve(__dirname, './setup-react-env.js')],
@@ -1,6 +1,41 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
1
3
  import { defineConfig, devices } from '@playwright/experimental-ct-react';
2
- // import { defineConfig as viteDefineConfig } from 'vite';
3
- // import react from '@vitejs/plugin-react';
4
+ import { findMonoRepoRoot } from '../jest/testing/utils.cjs';
5
+
6
+ // styled-components@5.3.11 currently resolves to two different pnpm store instances (one paired
7
+ // with react-is@18.3.1, one with react-is@19.2.8 — see pnpm/pnpm#11834: dedupePeerDependents
8
+ // fails to collapse peer-cyclic packages like styled-components <-> babel-plugin-styled-components).
9
+ // @xstyled/styled-components (used by ds-system's styled() wrapper and themeProviderHOC for theme
10
+ // merging) inherits that split per-consumer. Two module instances means two separate Context
11
+ // objects, so ThemeProvider from one instance is invisible to styled() calls resolved through the
12
+ // other, which is what actually breaks theme merging. This pins both packages to the single
13
+ // instance built against react-is@18.3.1. Resolved dynamically (not a hardcoded folder name)
14
+ // because the pnpm store path encodes @babel/core's version in its hash. Same fix as the Jest
15
+ // moduleNameMapper and the Storybook/Portal/react-18-vite resolve.alias entries — this is the
16
+ // Playwright component-testing runtime's own internal Vite instance, which none of those cover.
17
+ const resolvePinnedStyledComponentsAliases = () => {
18
+ const monorepoRoot = findMonoRepoRoot(process.cwd());
19
+ if (!monorepoRoot) return {};
20
+ const pnpmDir = path.join(monorepoRoot, 'node_modules', '.pnpm');
21
+ if (!fs.existsSync(pnpmDir)) return {};
22
+ const entries = fs.readdirSync(pnpmDir);
23
+ const scEntry = entries.find((e) => e.startsWith('styled-components@5.3.11') && e.includes('_react-is@18.3.1_'));
24
+ if (!scEntry) return {};
25
+ const styledComponentsPath = path.join(pnpmDir, scEntry, 'node_modules', 'styled-components');
26
+ const scRealPath = fs.realpathSync(styledComponentsPath);
27
+ const xscEntry = entries
28
+ .filter((e) => e.startsWith('@xstyled+styled-components@3.8.1'))
29
+ .find((e) => {
30
+ const nested = path.join(pnpmDir, e, 'node_modules', 'styled-components');
31
+ return fs.existsSync(nested) && fs.realpathSync(nested) === scRealPath;
32
+ });
33
+ if (!xscEntry) return {};
34
+ return {
35
+ 'styled-components': styledComponentsPath,
36
+ '@xstyled/styled-components': path.join(pnpmDir, xscEntry, 'node_modules', '@xstyled', 'styled-components'),
37
+ };
38
+ };
4
39
 
5
40
  export const config = defineConfig({
6
41
  testDir: './src/tests',
@@ -15,13 +50,21 @@ export const config = defineConfig({
15
50
  workers: process.env.CI ? 1 : undefined,
16
51
  /* Reporter to use. See https://playwright.dev/docs/test-reporters */
17
52
  reporter: 'list',
18
- // ctViteConfig: viteDefineConfig({ logLevel: 'info', plugins: [react()] }),
19
53
  use: {
20
54
  ctPort: 31500,
21
55
  headless: process.env.CI || process.env.PW_HEADLESS ? true : false,
22
56
  launchOptions: {
23
57
  devtools: process.env.CI || process.env.PW_HEADLESS ? false : true,
24
58
  },
59
+ // Note: ctViteConfig deep-merges with Playwright's own base/framework Vite config (see
60
+ // experimental-ct-core/lib/viteUtils.js — mergeConfig, then frameworkOverrides applied after).
61
+ // Do not add a `plugins` entry here — the React plugin is injected separately via
62
+ // frameworkOverrides regardless of what's passed here, so re-adding it would register it twice.
63
+ ctViteConfig: {
64
+ resolve: {
65
+ alias: resolvePinnedStyledComponentsAliases(),
66
+ },
67
+ },
25
68
  },
26
69
  projects: [
27
70
  {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elliemae/ds-monorepo-devops",
3
- "version": "3.70.0-next.49",
3
+ "version": "3.70.0-next.51",
4
4
  "license": "MIT",
5
5
  "description": "ICE MT - Dimsum - Monorepo Devops",
6
6
  "type": "module",