@servicetitan/startup 22.14.0 → 22.16.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/dist/cli/__mocks__/create-package.d.ts +3 -0
- package/dist/cli/__mocks__/create-package.d.ts.map +1 -0
- package/dist/cli/__mocks__/create-package.js +9 -0
- package/dist/cli/__mocks__/create-package.js.map +1 -0
- package/dist/cli/__mocks__/index.d.ts +2 -0
- package/dist/cli/__mocks__/index.d.ts.map +1 -0
- package/dist/cli/__mocks__/index.js +18 -0
- package/dist/cli/__mocks__/index.js.map +1 -0
- package/dist/cli/commands/eslint.d.ts +12 -0
- package/dist/cli/commands/eslint.d.ts.map +1 -0
- package/dist/cli/commands/eslint.js +47 -0
- package/dist/cli/commands/eslint.js.map +1 -0
- package/dist/cli/commands/index.d.ts +1 -0
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +1 -0
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/lint.d.ts +5 -0
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/commands/lint.js +22 -30
- package/dist/cli/commands/lint.js.map +1 -1
- package/dist/cli/index.js +20 -6
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/utils/eslint.d.ts +7 -0
- package/dist/cli/utils/eslint.d.ts.map +1 -0
- package/dist/cli/utils/eslint.js +57 -0
- package/dist/cli/utils/eslint.js.map +1 -0
- package/dist/cli/utils/index.d.ts +2 -0
- package/dist/cli/utils/index.d.ts.map +1 -1
- package/dist/cli/utils/index.js +2 -0
- package/dist/cli/utils/index.js.map +1 -1
- package/dist/cli/utils/set-node-options.d.ts +7 -0
- package/dist/cli/utils/set-node-options.d.ts.map +1 -0
- package/dist/cli/utils/set-node-options.js +46 -0
- package/dist/cli/utils/set-node-options.js.map +1 -0
- package/dist/cli/utils/tcm.d.ts.map +1 -1
- package/dist/cli/utils/tcm.js +3 -1
- package/dist/cli/utils/tcm.js.map +1 -1
- package/dist/utils/get-configuration.d.ts +5 -1
- package/dist/utils/get-configuration.d.ts.map +1 -1
- package/dist/utils/get-configuration.js +2 -2
- package/dist/utils/get-configuration.js.map +1 -1
- package/dist/utils/get-jest-config.d.ts +1 -1
- package/dist/utils/get-jest-config.d.ts.map +1 -1
- package/dist/utils/get-jest-config.js +8 -6
- package/dist/utils/get-jest-config.js.map +1 -1
- package/dist/utils/get-package-data.js +3 -3
- package/dist/utils/get-package-data.js.map +1 -1
- package/dist/utils/get-package-name.d.ts.map +1 -1
- package/dist/utils/get-package-name.js +2 -2
- package/dist/utils/get-package-name.js.map +1 -1
- package/dist/utils/get-packages.js +8 -7
- package/dist/utils/get-packages.js.map +1 -1
- package/dist/webpack/shared.config.d.ts.map +1 -1
- package/dist/webpack/shared.config.js +1 -0
- package/dist/webpack/shared.config.js.map +1 -1
- package/package.json +4 -4
- package/src/cli/__mocks__/create-package.ts +12 -0
- package/src/cli/__mocks__/index.ts +1 -0
- package/src/cli/commands/__tests__/build.test.ts +135 -0
- package/src/cli/commands/__tests__/bundle-package.test.ts +72 -0
- package/src/cli/commands/__tests__/eslint.test.ts +19 -0
- package/src/cli/commands/__tests__/init.test.ts +42 -0
- package/src/cli/commands/__tests__/lint.test.ts +114 -0
- package/src/cli/commands/__tests__/mfe-package-clean.test.ts +193 -0
- package/src/cli/commands/__tests__/mfe-package-publish.test.ts +192 -0
- package/src/cli/commands/__tests__/mfe-publish.test.ts +172 -0
- package/src/cli/commands/__tests__/prepare-package.test.ts +75 -0
- package/src/cli/commands/__tests__/start.test.ts +111 -0
- package/src/cli/commands/__tests__/styles-check.test.ts +119 -0
- package/src/cli/commands/__tests__/tests.test.ts +43 -0
- package/src/cli/commands/eslint.ts +19 -0
- package/src/cli/commands/index.ts +1 -0
- package/src/cli/commands/lint.ts +29 -42
- package/src/cli/index.ts +17 -5
- package/src/cli/utils/__tests__/assets-copy.test.ts +48 -52
- package/src/cli/utils/__tests__/bundle.test.ts +361 -0
- package/src/cli/utils/__tests__/cli-git.test.ts +28 -0
- package/src/cli/utils/__tests__/cli-npm.test.ts +166 -0
- package/src/cli/utils/__tests__/cli-os.test.ts +103 -0
- package/src/cli/utils/__tests__/eslint.test.ts +91 -0
- package/src/cli/utils/__tests__/get-module-type.test.ts +56 -0
- package/src/cli/utils/__tests__/is-module-installed.test.ts +24 -0
- package/src/cli/utils/__tests__/set-node-options.test.ts +131 -0
- package/src/cli/utils/__tests__/styles-copy.test.ts +48 -44
- package/src/cli/utils/__tests__/tcm.test.ts +101 -192
- package/src/cli/utils/__tests__/tsc.test.ts +85 -0
- package/src/cli/utils/eslint.ts +50 -0
- package/src/cli/utils/index.ts +2 -0
- package/src/cli/utils/set-node-options.ts +45 -0
- package/src/cli/utils/tcm.ts +3 -1
- package/src/utils/__tests__/get-configuration.test.ts +215 -16
- package/src/utils/__tests__/get-destination-folders.test.ts +65 -0
- package/src/utils/__tests__/get-jest-config.test.ts +134 -0
- package/src/utils/__tests__/get-package-data.test.ts +90 -0
- package/src/utils/__tests__/get-packages.test.ts +165 -0
- package/src/utils/__tests__/get-tsconfig.test.ts +48 -0
- package/src/utils/__tests__/log.test.ts +123 -0
- package/src/utils/__tests__/to-array.test.ts +19 -0
- package/src/utils/get-configuration.ts +8 -3
- package/src/utils/get-jest-config.ts +3 -1
- package/src/utils/get-package-data.ts +1 -1
- package/src/utils/get-package-name.ts +1 -2
- package/src/utils/get-packages.ts +2 -2
- package/src/webpack/shared.config.ts +1 -0
- package/template/package.json +8 -1
- package/template/packages/application/package.json +5 -0
- package/template/packages/application/src/__tests__/app.test.tsx +33 -0
- package/template/packages/application/src/app.tsx +9 -6
- package/template/packages/application/src/main-page.tsx +5 -0
- package/template/packages/application/src/second-page.tsx +5 -0
- package/template/setupTests.ts +27 -0
- package/template/tsconfig.test.json +1 -1
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import execa from 'execa';
|
|
2
|
+
import { isBundle, isLegacy } from '../get-configuration';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
Package,
|
|
6
|
+
PackageType,
|
|
7
|
+
getPackages,
|
|
8
|
+
getPackagesGraph,
|
|
9
|
+
splitPackagesByType,
|
|
10
|
+
} from '../get-packages';
|
|
11
|
+
|
|
12
|
+
jest.mock('execa', () => ({ sync: jest.fn() }));
|
|
13
|
+
jest.mock('../get-configuration');
|
|
14
|
+
|
|
15
|
+
describe('[startup] Utils', () => {
|
|
16
|
+
const packages: Pick<Package, 'name' | 'location' | 'type'>[] = [
|
|
17
|
+
{ name: 'foo', location: 'packages/foo', type: PackageType.Legacy },
|
|
18
|
+
{ name: 'bar', location: 'packages/bar', type: PackageType.TSC },
|
|
19
|
+
{ name: 'baz', location: 'packages/baz', type: PackageType.Webpack },
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
describe(`${getPackages.name}`, () => {
|
|
23
|
+
let options: Parameters<typeof getPackages>[0] | undefined;
|
|
24
|
+
let dependencies: Record<string, string[]> | undefined;
|
|
25
|
+
|
|
26
|
+
function findPackageByLocation(location?: string) {
|
|
27
|
+
return packages.find(p => p.location === location);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function packageGraph() {
|
|
31
|
+
return dependencies ?? Object.fromEntries(packages.map(({ name }) => [name, []]));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function scopedPackages() {
|
|
35
|
+
let result = packages;
|
|
36
|
+
if (options?.scope) {
|
|
37
|
+
const arrayScope = Array.isArray(options.scope) ? options.scope : [options.scope];
|
|
38
|
+
result = result.filter(({ name }) => arrayScope.includes(name));
|
|
39
|
+
}
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
beforeEach(() => {
|
|
44
|
+
options = undefined;
|
|
45
|
+
dependencies = undefined;
|
|
46
|
+
|
|
47
|
+
jest.mocked(isBundle).mockImplementation(
|
|
48
|
+
location => findPackageByLocation(location)?.type === PackageType.Webpack
|
|
49
|
+
);
|
|
50
|
+
jest.mocked(isLegacy).mockImplementation(
|
|
51
|
+
location => findPackageByLocation(location)?.type === PackageType.Legacy
|
|
52
|
+
);
|
|
53
|
+
// @ts-expect-error because implementation doesn't match all exec.sync signatures
|
|
54
|
+
jest.mocked(execa.sync).mockImplementation((_: string, args: string[]): any => {
|
|
55
|
+
return {
|
|
56
|
+
stdout: JSON.stringify(
|
|
57
|
+
args.includes('--graph')
|
|
58
|
+
? packageGraph()
|
|
59
|
+
: args.includes('--scope')
|
|
60
|
+
? scopedPackages().map(({ type, ...pkg }) => pkg)
|
|
61
|
+
: packages.map(({ type, ...pkg }) => pkg)
|
|
62
|
+
),
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
const subject = () => getPackages(options);
|
|
68
|
+
|
|
69
|
+
test('returns lerna packages with type metadata', () => {
|
|
70
|
+
expect(subject()).toEqual(packages);
|
|
71
|
+
expect(execa.sync).toHaveBeenCalledWith('npx', 'lerna la --json'.split(' '));
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe.each(['scope', 'ignore'])('with "%s"', option => {
|
|
75
|
+
beforeEach(() => (options = { [option]: 'foo' }));
|
|
76
|
+
|
|
77
|
+
test(`passes "${option}" option to lerna`, () => {
|
|
78
|
+
subject();
|
|
79
|
+
|
|
80
|
+
expect(execa.sync).toHaveBeenCalledWith(
|
|
81
|
+
'npx',
|
|
82
|
+
`lerna la --${option} foo --json`.split(' ')
|
|
83
|
+
);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe('with "scope"', () => {
|
|
88
|
+
beforeEach(() => (options = { scope: 'foo' }));
|
|
89
|
+
|
|
90
|
+
test('returns filtered packages', () => {
|
|
91
|
+
expect(subject()).toEqual(packages.filter(({ name }) => name === 'foo'));
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe('when filtered package has dependencies', () => {
|
|
95
|
+
beforeEach(() => (dependencies = { ...packageGraph(), foo: ['bar', 'external'] }));
|
|
96
|
+
|
|
97
|
+
test('also returns internal dependencies', () => {
|
|
98
|
+
expect(subject()).toEqual(
|
|
99
|
+
packages.filter(({ name }) => ['foo', 'bar'].includes(name))
|
|
100
|
+
);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
describe(`${getPackagesGraph.name}`, () => {
|
|
107
|
+
const packageGraph = Object.fromEntries(packages.map(({ name }) => [name, []]));
|
|
108
|
+
let options: Parameters<typeof getPackagesGraph>[0] | undefined;
|
|
109
|
+
|
|
110
|
+
beforeEach(() => {
|
|
111
|
+
options = undefined;
|
|
112
|
+
jest.mocked(execa.sync).mockImplementation((): any => ({
|
|
113
|
+
stdout: JSON.stringify(packageGraph),
|
|
114
|
+
}));
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
const subject = () => getPackagesGraph(options);
|
|
118
|
+
|
|
119
|
+
test('returns lerna package graph', () => {
|
|
120
|
+
expect(subject()).toEqual(packageGraph);
|
|
121
|
+
expect(execa.sync).toHaveBeenCalledWith('npx', 'lerna la --graph'.split(' '));
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
describe.each(['scope', 'ignore'])('with "%s"', option => {
|
|
125
|
+
beforeEach(() => (options = { [option]: 'foo' }));
|
|
126
|
+
|
|
127
|
+
test(`passes "${option}" option to lerna`, () => {
|
|
128
|
+
subject();
|
|
129
|
+
|
|
130
|
+
expect(execa.sync).toHaveBeenCalledWith(
|
|
131
|
+
'npx',
|
|
132
|
+
`lerna la --${option} foo --graph`.split(' ')
|
|
133
|
+
);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
describe(`${splitPackagesByType.name}`, () => {
|
|
139
|
+
const subject = (packages: Package[]) => splitPackagesByType(packages as Package[]);
|
|
140
|
+
|
|
141
|
+
test('groups packages by type', () => {
|
|
142
|
+
expect(subject(packages as Package[])).toEqual(
|
|
143
|
+
packages.reduce<ReturnType<typeof splitPackagesByType>>(
|
|
144
|
+
(result, pkg) => {
|
|
145
|
+
result[pkg.type].push(pkg as Package);
|
|
146
|
+
return result;
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
[PackageType.TSC]: [],
|
|
150
|
+
[PackageType.Webpack]: [],
|
|
151
|
+
[PackageType.Legacy]: [],
|
|
152
|
+
}
|
|
153
|
+
)
|
|
154
|
+
);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test('grouping always includes all types', () => {
|
|
158
|
+
expect(subject([])).toEqual({
|
|
159
|
+
[PackageType.TSC]: [],
|
|
160
|
+
[PackageType.Webpack]: [],
|
|
161
|
+
[PackageType.Legacy]: [],
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
});
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import mockFS from 'mock-fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
|
|
4
|
+
import { getTsConfig } from '../get-tsconfig';
|
|
5
|
+
|
|
6
|
+
describe(`[startup] Utils`, () => {
|
|
7
|
+
describe(`${getTsConfig.name}`, () => {
|
|
8
|
+
const defaultConfig = 'tsconfig.json';
|
|
9
|
+
const buildConfig = 'tsconfig.build.json';
|
|
10
|
+
let location: string | undefined;
|
|
11
|
+
|
|
12
|
+
const subject = () => getTsConfig(location);
|
|
13
|
+
|
|
14
|
+
beforeEach(() => (location = undefined));
|
|
15
|
+
|
|
16
|
+
afterEach(() => mockFS.restore());
|
|
17
|
+
|
|
18
|
+
test(`returns ${defaultConfig}`, () => {
|
|
19
|
+
expect(subject()).toBe(defaultConfig);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
describe(`when ${buildConfig} is present`, () => {
|
|
23
|
+
beforeEach(() => mockFS({ [buildConfig]: JSON.stringify({}) }));
|
|
24
|
+
|
|
25
|
+
test(`returns ${buildConfig}`, () => {
|
|
26
|
+
expect(subject()).toBe(buildConfig);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
describe('when passed a location', () => {
|
|
31
|
+
beforeEach(() => (location = 'packages/foo'));
|
|
32
|
+
|
|
33
|
+
test(`returns {location}/${defaultConfig}`, () => {
|
|
34
|
+
expect(subject()).toBe(path.join(location!, defaultConfig));
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe(`when ${buildConfig} is present`, () => {
|
|
38
|
+
beforeEach(() => {
|
|
39
|
+
mockFS({ packages: { foo: { [buildConfig]: JSON.stringify({}) } } });
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test(`returns {location}/${buildConfig}`, () => {
|
|
43
|
+
expect(subject()).toBe(path.join(location!, buildConfig));
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { log, logErrors } from '../log';
|
|
3
|
+
|
|
4
|
+
describe(`[startup] Utils`, () => {
|
|
5
|
+
describe('log', () => {
|
|
6
|
+
const message = 'foo';
|
|
7
|
+
let stdoutSpy: jest.SpyInstance;
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
jest.resetAllMocks();
|
|
11
|
+
stdoutSpy = jest.spyOn(process.stdout, 'write').mockImplementation(jest.fn());
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test('info() writes cyan text', () => {
|
|
15
|
+
log.info(message);
|
|
16
|
+
|
|
17
|
+
expect(stdoutSpy).toHaveBeenCalledWith(`${chalk.bold.cyan(message)}\n`);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test('success() writes green text', () => {
|
|
21
|
+
log.success(message);
|
|
22
|
+
|
|
23
|
+
expect(stdoutSpy).toHaveBeenCalledWith(`${chalk.bold.green(message)}\n`);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('warning() writes orange text', () => {
|
|
27
|
+
log.warning(message);
|
|
28
|
+
|
|
29
|
+
expect(stdoutSpy).toHaveBeenCalledWith(`${chalk.bold.keyword('orange')(message)}\n`);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('log error writes red text', () => {
|
|
33
|
+
log.error(message);
|
|
34
|
+
|
|
35
|
+
expect(stdoutSpy).toHaveBeenCalledWith(`${chalk.bold.red(message)}\n`);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe(`${logErrors.name}`, () => {
|
|
40
|
+
const error = new Error('Oops!');
|
|
41
|
+
|
|
42
|
+
class SubjectClass {
|
|
43
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
44
|
+
private _foo: boolean;
|
|
45
|
+
|
|
46
|
+
constructor() {
|
|
47
|
+
this._foo = false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
@logErrors
|
|
51
|
+
execute(callback: Function) {
|
|
52
|
+
return callback();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@logErrors
|
|
56
|
+
async executeAsync(callback: Function) {
|
|
57
|
+
await callback();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@logErrors
|
|
61
|
+
get foo() {
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
set foo(value: boolean) {
|
|
66
|
+
this._foo = value;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const instance = new SubjectClass();
|
|
71
|
+
|
|
72
|
+
beforeEach(() => {
|
|
73
|
+
jest.resetAllMocks();
|
|
74
|
+
jest.spyOn(log, 'error').mockImplementation(jest.fn());
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe('when decorated function raises no error', () => {
|
|
78
|
+
const subject = () => instance.execute(jest.fn());
|
|
79
|
+
|
|
80
|
+
test('logs nothing', () => {
|
|
81
|
+
subject();
|
|
82
|
+
|
|
83
|
+
expect(log.error).not.toHaveBeenCalled();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe('when decorated function throws error', () => {
|
|
88
|
+
const subject = () =>
|
|
89
|
+
instance.execute(() => {
|
|
90
|
+
throw error;
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test('logs error', () => {
|
|
94
|
+
expect(subject).toThrowError(error);
|
|
95
|
+
|
|
96
|
+
expect(log.error).toHaveBeenCalledWith(String(error));
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
describe('when decorated asynchronous function throws error', () => {
|
|
101
|
+
const subject = async () =>
|
|
102
|
+
instance.executeAsync(() => {
|
|
103
|
+
throw error;
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test('logs error', async () => {
|
|
107
|
+
await expect(subject).rejects.toThrowError(error);
|
|
108
|
+
|
|
109
|
+
expect(log.error).toHaveBeenCalledWith(String(error));
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe('when decorated accessor throws error', () => {
|
|
114
|
+
const subject = () => instance.foo;
|
|
115
|
+
|
|
116
|
+
test('logs nothing', () => {
|
|
117
|
+
expect(subject).toThrowError(error);
|
|
118
|
+
|
|
119
|
+
expect(log.error).not.toHaveBeenCalled();
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { toArray } from '../to-array';
|
|
2
|
+
|
|
3
|
+
describe(`[startup] Utils`, () => {
|
|
4
|
+
describe(`${toArray.name}`, () => {
|
|
5
|
+
const subject = (value: any) => toArray(value);
|
|
6
|
+
|
|
7
|
+
test('when value is an Array, returns the value ', () => {
|
|
8
|
+
[[], [''], [null]].forEach(value => expect(subject(value)).toBe(value));
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test('when value is not an Array, wraps value within array', () => {
|
|
12
|
+
['', null, 'foo', {}].forEach(value => expect(subject(value)).toEqual([value]));
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test('when value us undefined, returns []', () => {
|
|
16
|
+
expect(subject(undefined)).toEqual([]);
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
});
|
|
@@ -5,8 +5,7 @@ import { Configuration as WebpackDevServerConfiguration } from 'webpack-dev-serv
|
|
|
5
5
|
import { ESLint } from 'eslint';
|
|
6
6
|
import { LinterOptions } from 'stylelint';
|
|
7
7
|
import { Config } from '@jest/types';
|
|
8
|
-
|
|
9
|
-
import { readJson } from '.';
|
|
8
|
+
import { readJson } from './read-json';
|
|
10
9
|
|
|
11
10
|
const allowedWebpackDevServerOptions = ['headers', 'port', 'proxy', 'contentBase'] as const;
|
|
12
11
|
|
|
@@ -34,7 +33,13 @@ export interface StylelintConfiguration extends Partial<LinterOptions> {
|
|
|
34
33
|
|
|
35
34
|
export type JestConfiguration = Omit<Config.Argv, '_' | '$0'>;
|
|
36
35
|
|
|
37
|
-
interface
|
|
36
|
+
export interface NodeConfiguration {
|
|
37
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
38
|
+
NODE_OPTIONS?: string[];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface Configuration extends NodeConfiguration {
|
|
42
|
+
[key: string]: any;
|
|
38
43
|
'webpack'?: false | WebpackConfiguration;
|
|
39
44
|
'web-component'?: boolean;
|
|
40
45
|
'legacy'?: boolean;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
2
|
import { Config } from '@jest/types';
|
|
3
|
-
import {
|
|
3
|
+
import { JestConfiguration, getJestConfiguration } from './get-configuration';
|
|
4
|
+
import { getDestinationFolders } from './get-destination-folders';
|
|
5
|
+
import { toArray } from './to-array';
|
|
4
6
|
|
|
5
7
|
const getJestConfigBase = (
|
|
6
8
|
stringify: boolean,
|
package/template/package.json
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"@servicetitan/design-system": "^12.10.0",
|
|
11
11
|
"@servicetitan/link-item": "^23.1.0",
|
|
12
|
+
"@servicetitan/react-ioc": "^22.15.0",
|
|
12
13
|
"feature-a": "^0.0.0",
|
|
13
14
|
"feature-b": "^0.0.0",
|
|
14
15
|
"feature-c": "^0.0.0",
|
|
@@ -17,6 +18,10 @@
|
|
|
17
18
|
"react-router-dom": "^5.3.0"
|
|
18
19
|
},
|
|
19
20
|
"devDependencies": {
|
|
21
|
+
"@servicetitan/testing-library": "^0.3.0",
|
|
22
|
+
"@testing-library/jest-dom": "^5.17.0",
|
|
23
|
+
"@testing-library/react": "^12.1.5",
|
|
24
|
+
"@testing-library/react-hooks": "^8.0.1",
|
|
20
25
|
"@types/react": "^17.0.37",
|
|
21
26
|
"@types/react-dom": "^17.0.11",
|
|
22
27
|
"@types/react-router-dom": "^5.3.2"
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { mockComponent, mockLocation } from '@servicetitan/testing-library';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
|
|
4
|
+
import { App } from '../app';
|
|
5
|
+
|
|
6
|
+
jest.mock('../main-page', () => mockComponent('MainPage'));
|
|
7
|
+
jest.mock('../second-page', () => mockComponent('SecondPage'));
|
|
8
|
+
|
|
9
|
+
describe(`${App.name}`, () => {
|
|
10
|
+
const subject = () => render(<App />);
|
|
11
|
+
|
|
12
|
+
test('renders sidebar', () => {
|
|
13
|
+
subject();
|
|
14
|
+
|
|
15
|
+
expect(screen.getByRole('link', { name: 'Main page' })).toBeInTheDocument();
|
|
16
|
+
expect(screen.getByRole('link', { name: 'Second page' })).toBeInTheDocument();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const routes = Object.entries({
|
|
20
|
+
MainPage: '/',
|
|
21
|
+
SecondPage: '/second-page',
|
|
22
|
+
}).map(([component, path]) => ({ component, path }));
|
|
23
|
+
|
|
24
|
+
describe.each(routes)('when location is $path', ({ component, path }) => {
|
|
25
|
+
beforeEach(() => mockLocation(path));
|
|
26
|
+
|
|
27
|
+
test(`renders <${component} />`, () => {
|
|
28
|
+
subject();
|
|
29
|
+
|
|
30
|
+
expect(screen).toContainComponent(component);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
});
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { StrictMode,
|
|
1
|
+
import { StrictMode, FC } from 'react';
|
|
2
2
|
import { BrowserRouter, Switch, Route } from 'react-router-dom';
|
|
3
3
|
import { SideNav, Frame, Page, Sidebar } from '@servicetitan/design-system';
|
|
4
4
|
import { SideNavLinkItem } from '@servicetitan/link-item';
|
|
5
5
|
|
|
6
|
+
import { SecondPage } from './second-page';
|
|
7
|
+
import { MainPage } from './main-page';
|
|
6
8
|
import './design-system.css';
|
|
7
9
|
import './app.css';
|
|
8
10
|
|
|
@@ -28,11 +30,12 @@ export const App: FC = () => (
|
|
|
28
30
|
maxWidth="wide"
|
|
29
31
|
>
|
|
30
32
|
<Switch>
|
|
31
|
-
<Route path="/" exact
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
<Route path="/" exact>
|
|
34
|
+
<MainPage />
|
|
35
|
+
</Route>
|
|
36
|
+
<Route path="/second-page">
|
|
37
|
+
<SecondPage />
|
|
38
|
+
</Route>
|
|
36
39
|
</Switch>
|
|
37
40
|
</Page>
|
|
38
41
|
</Frame>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import '@servicetitan/testing-library';
|
|
2
|
+
import '@testing-library/jest-dom';
|
|
3
|
+
|
|
4
|
+
Object.defineProperties(window, {
|
|
5
|
+
location: { value: window.location, writable: true, configurable: true },
|
|
6
|
+
matchMedia: {
|
|
7
|
+
value: jest.fn().mockImplementation(query => ({
|
|
8
|
+
matches: false,
|
|
9
|
+
media: query,
|
|
10
|
+
onChange: null,
|
|
11
|
+
addEventListener: jest.fn(),
|
|
12
|
+
removeEventListener: jest.fn(),
|
|
13
|
+
dispatchEvent: jest.fn(),
|
|
14
|
+
})),
|
|
15
|
+
writable: true,
|
|
16
|
+
configurable: true,
|
|
17
|
+
},
|
|
18
|
+
ResizeObserver: {
|
|
19
|
+
value: jest.fn().mockImplementation(() => ({
|
|
20
|
+
disconnect: jest.fn(),
|
|
21
|
+
observe: jest.fn(),
|
|
22
|
+
unobserve: jest.fn(),
|
|
23
|
+
})),
|
|
24
|
+
writable: true,
|
|
25
|
+
configurable: true,
|
|
26
|
+
},
|
|
27
|
+
});
|