@shopgate/webpack 7.32.2-alpha.9 → 7.33.0-beta.2

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.
@@ -0,0 +1,67 @@
1
+ const ERROR_IN_FILE = /^(.+?)\((\d+),(\d+)\): error (TS\d+): (.*)$/;
2
+ const ERROR_WITHOUT_FILE = /^error (TS\d+): (.*)$/;
3
+ const CHECK_STARTED = /Starting (incremental )?compilation/;
4
+ const CHECK_FINISHED = /Found \d+ errors?\. Watching for file changes/;
5
+
6
+ /**
7
+ * @typedef {Object} TypeCheckError
8
+ * @property {string|null} file The file as the compiler printed it, relative to the project.
9
+ * @property {number|null} line The line of the error.
10
+ * @property {number|null} column The column of the error.
11
+ * @property {string} code The error code, e.g. "TS2322".
12
+ * @property {string} message The error message.
13
+ */
14
+
15
+ /**
16
+ * @typedef {Object} TypeCheckEvent
17
+ * @property {'started'|'finished'} type Whether a check started or finished.
18
+ * @property {TypeCheckError[]} [errors] The errors of a finished check.
19
+ */
20
+
21
+ /**
22
+ * Creates a parser for the output of "tsc --watch --pretty false". It takes the output line by
23
+ * line and returns an event when a check starts or finishes.
24
+ * @return {function(string): TypeCheckEvent|null}
25
+ */
26
+ module.exports = function createTypeCheckParser() {
27
+ let errors = [];
28
+
29
+ return (line) => {
30
+ if (CHECK_STARTED.test(line)) {
31
+ errors = [];
32
+ return { type: 'started' };
33
+ }
34
+
35
+ if (CHECK_FINISHED.test(line)) {
36
+ return {
37
+ type: 'finished',
38
+ errors,
39
+ };
40
+ }
41
+
42
+ const inFile = line.match(ERROR_IN_FILE);
43
+ const withoutFile = line.match(ERROR_WITHOUT_FILE);
44
+
45
+ if (inFile) {
46
+ errors.push({
47
+ file: inFile[1],
48
+ line: Number(inFile[2]),
49
+ column: Number(inFile[3]),
50
+ code: inFile[4],
51
+ message: inFile[5],
52
+ });
53
+ } else if (withoutFile) {
54
+ errors.push({
55
+ file: null,
56
+ line: null,
57
+ column: null,
58
+ code: withoutFile[1],
59
+ message: withoutFile[2],
60
+ });
61
+ } else if (/^\s+\S/.test(line) && errors.length > 0) {
62
+ errors[errors.length - 1].message += `\n${line}`;
63
+ }
64
+
65
+ return null;
66
+ };
67
+ };
@@ -0,0 +1,76 @@
1
+ const createTypeCheckParser = require('./createTypeCheckParser');
2
+
3
+ /**
4
+ * Feeds lines to a new parser and returns the events it emits.
5
+ * @param {string[]} lines The compiler output.
6
+ * @return {Object[]}
7
+ */
8
+ const parseLines = (lines) => {
9
+ const parse = createTypeCheckParser();
10
+
11
+ return lines.map(line => parse(line)).filter(Boolean);
12
+ };
13
+
14
+ describe('createTypeCheckParser', () => {
15
+ it('reports the start and the errors of a check', () => {
16
+ expect(parseLines([
17
+ '2:36:55 PM - Starting compilation in watch mode...',
18
+ '',
19
+ "portals/Banner/index.tsx(33,68): error TS2322: Type 'false' is not assignable to type 'true'.",
20
+ 'error TS6053: File not found.',
21
+ '',
22
+ '2:36:58 PM - Found 2 errors. Watching for file changes.',
23
+ ])).toEqual([
24
+ { type: 'started' },
25
+ {
26
+ type: 'finished',
27
+ errors: [
28
+ {
29
+ file: 'portals/Banner/index.tsx',
30
+ line: 33,
31
+ column: 68,
32
+ code: 'TS2322',
33
+ message: "Type 'false' is not assignable to type 'true'.",
34
+ },
35
+ {
36
+ file: null,
37
+ line: null,
38
+ column: null,
39
+ code: 'TS6053',
40
+ message: 'File not found.',
41
+ },
42
+ ],
43
+ },
44
+ ]);
45
+ });
46
+
47
+ it('adds indented lines to the message of the error before', () => {
48
+ const [, finished] = parseLines([
49
+ '02:36:48 PM - Starting compilation in watch mode...',
50
+ "a.ts(1,14): error TS2345: Argument of type 'A' is not assignable to parameter of type 'B'.",
51
+ " Property 'id' is missing in type 'A'.",
52
+ '02:36:49 PM - Found 1 error. Watching for file changes.',
53
+ ]);
54
+
55
+ expect(finished.errors).toHaveLength(1);
56
+ expect(finished.errors[0].message).toBe([
57
+ "Argument of type 'A' is not assignable to parameter of type 'B'.",
58
+ " Property 'id' is missing in type 'A'.",
59
+ ].join('\n'));
60
+ });
61
+
62
+ it('forgets the errors of the check before when a new one starts', () => {
63
+ const events = parseLines([
64
+ '2:36:55 PM - Starting compilation in watch mode...',
65
+ "a.ts(1,14): error TS2322: Type 'string' is not assignable to type 'number'.",
66
+ '2:36:58 PM - Found 1 error. Watching for file changes.',
67
+ '2:37:10 PM - File change detected. Starting incremental compilation...',
68
+ '2:37:11 PM - Found 0 errors. Watching for file changes.',
69
+ ]);
70
+
71
+ expect(events[3]).toEqual({
72
+ type: 'finished',
73
+ errors: [],
74
+ });
75
+ });
76
+ });
@@ -0,0 +1,55 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ /**
5
+ * @typedef {Object} TypeCheckProject
6
+ * @property {string} name The name that is shown in front of the output of the project.
7
+ * @property {string} path The folder that contains the tsconfig.json of the project.
8
+ * @property {boolean} isTheme Whether the project is the theme.
9
+ * @property {string|null} tsc The TypeScript compiler of the project, when it has one installed.
10
+ */
11
+
12
+ /**
13
+ * Resolves the TypeScript compiler that a project has installed.
14
+ * @param {string} projectPath The folder of the project.
15
+ * @return {string|null}
16
+ */
17
+ function resolveCompiler(projectPath) {
18
+ try {
19
+ const packagePath = require.resolve('typescript/package.json', { paths: [projectPath] });
20
+ // eslint-disable-next-line global-require, import/no-dynamic-require
21
+ const { bin } = require(packagePath);
22
+
23
+ return path.resolve(path.dirname(packagePath), bin.tsc);
24
+ } catch (error) {
25
+ return null;
26
+ }
27
+ }
28
+
29
+ /**
30
+ * Returns the theme and the frontends of the attached extensions that have a tsconfig.json.
31
+ * @param {string} themePath The folder of the theme.
32
+ * @param {Object} [extensions={}] The attached extensions.
33
+ * @return {TypeCheckProject[]}
34
+ */
35
+ module.exports = function getTypeCheckProjects(themePath, extensions = {}) {
36
+ const extensionsPath = path.resolve(themePath, '..', '..', 'extensions');
37
+
38
+ return [
39
+ {
40
+ name: path.basename(themePath),
41
+ path: themePath,
42
+ isTheme: true,
43
+ },
44
+ ...Object.keys(extensions).map(id => ({
45
+ name: id,
46
+ path: path.resolve(extensionsPath, extensions[id].path, 'frontend'),
47
+ isTheme: false,
48
+ })),
49
+ ]
50
+ .filter(project => fs.existsSync(path.join(project.path, 'tsconfig.json')))
51
+ .map(project => ({
52
+ ...project,
53
+ tsc: resolveCompiler(project.path),
54
+ }));
55
+ };
@@ -0,0 +1,83 @@
1
+ const fs = require('fs');
2
+ const os = require('os');
3
+ const path = require('path');
4
+ const getTypeCheckProjects = require('./getTypeCheckProjects');
5
+
6
+ describe('getTypeCheckProjects', () => {
7
+ let root;
8
+ let themePath;
9
+
10
+ const write = (file, content = '{}') => {
11
+ const target = path.join(root, file);
12
+ fs.mkdirSync(path.dirname(target), { recursive: true });
13
+ fs.writeFileSync(target, content);
14
+ };
15
+
16
+ beforeEach(() => {
17
+ root = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'type-check-')));
18
+ themePath = path.join(root, 'themes', 'theme-test');
19
+ fs.mkdirSync(themePath, { recursive: true });
20
+ });
21
+
22
+ afterEach(() => {
23
+ fs.rmSync(root, {
24
+ recursive: true,
25
+ force: true,
26
+ });
27
+ });
28
+
29
+ it('returns the theme and the attached extensions that have a tsconfig', () => {
30
+ write('themes/theme-test/tsconfig.json');
31
+ write('extensions/typed/frontend/tsconfig.json');
32
+ write('extensions/untyped/frontend/index.js', '');
33
+ write('extensions/detached/frontend/tsconfig.json');
34
+
35
+ const projects = getTypeCheckProjects(themePath, {
36
+ '@acme/typed': { path: 'typed' },
37
+ '@acme/untyped': { path: 'untyped' },
38
+ });
39
+
40
+ expect(projects.map(({ name, path: projectPath, isTheme }) => ({
41
+ name,
42
+ path: projectPath,
43
+ isTheme,
44
+ }))).toEqual([
45
+ {
46
+ name: 'theme-test',
47
+ path: themePath,
48
+ isTheme: true,
49
+ },
50
+ {
51
+ name: '@acme/typed',
52
+ path: path.join(root, 'extensions', 'typed', 'frontend'),
53
+ isTheme: false,
54
+ },
55
+ ]);
56
+ });
57
+
58
+ it('leaves out a theme without a tsconfig', () => {
59
+ expect(getTypeCheckProjects(themePath)).toEqual([]);
60
+ });
61
+
62
+ it('resolves the compiler that the project has installed', () => {
63
+ write('extensions/typed/frontend/tsconfig.json');
64
+ write(
65
+ 'extensions/typed/frontend/node_modules/typescript/package.json',
66
+ JSON.stringify({ bin: { tsc: './bin/tsc' } })
67
+ );
68
+
69
+ const [project] = getTypeCheckProjects(themePath, { '@acme/typed': { path: 'typed' } });
70
+
71
+ expect(project.tsc).toBe(path.join(
72
+ root, 'extensions', 'typed', 'frontend', 'node_modules', 'typescript', 'bin', 'tsc'
73
+ ));
74
+ });
75
+
76
+ it('reports no compiler when the project has none installed', () => {
77
+ write('extensions/typed/frontend/tsconfig.json');
78
+
79
+ const [project] = getTypeCheckProjects(themePath, { '@acme/typed': { path: 'typed' } });
80
+
81
+ expect(project.tsc).toBeNull();
82
+ });
83
+ });
@@ -0,0 +1,48 @@
1
+ const { spawn, spawnSync } = require('child_process');
2
+
3
+ const isWindows = process.platform === 'win32';
4
+ const STOP_SIGNALS = ['SIGINT', 'SIGTERM', 'SIGHUP'];
5
+
6
+ const child = spawn(process.execPath, process.argv.slice(2), {
7
+ stdio: ['ignore', 'inherit', 'inherit'],
8
+ detached: !isWindows,
9
+ windowsHide: true,
10
+ });
11
+
12
+ /**
13
+ * Stops the compiler together with every process it started, then exits without an error.
14
+ */
15
+ function stop() {
16
+ try {
17
+ if (isWindows) {
18
+ const { error, status } = spawnSync('taskkill', ['/pid', String(child.pid), '/T', '/F'], {
19
+ windowsHide: true,
20
+ });
21
+
22
+ if (error || status !== 0) {
23
+ child.kill();
24
+ }
25
+ } else {
26
+ process.kill(-child.pid, 'SIGTERM');
27
+ }
28
+ } catch (error) {
29
+ child.kill();
30
+ }
31
+
32
+ process.exit(0);
33
+ }
34
+
35
+ process.stdin.on('end', stop);
36
+ process.stdin.on('error', stop);
37
+ process.stdin.resume();
38
+ STOP_SIGNALS.forEach(signal => process.on(signal, stop));
39
+
40
+ child.on('exit', (code, signal) => {
41
+ if (signal) {
42
+ process.removeAllListeners(signal);
43
+ process.kill(process.pid, signal);
44
+ return;
45
+ }
46
+
47
+ process.exit(code || 1);
48
+ });
@@ -1,9 +1,9 @@
1
- import React from 'react';
2
- import { mount } from 'enzyme';
1
+ import { render } from '@testing-library/react';
3
2
  import Conditioner from '@shopgate/pwa-core/classes/Conditioner';
4
3
  import ProductCharacteristics from './index';
5
4
 
6
5
  const mockedConditioner = new Conditioner();
6
+ const mockedSetCharacteristics = jest.fn();
7
7
  const mockedMapStateToPropsResult = {
8
8
  variants: {
9
9
  products: [{
@@ -59,7 +59,7 @@ jest.mock('@shopgate/pwa-common/context', () => ({
59
59
  productId="123"
60
60
  variantId="123-45"
61
61
  conditioner={mockedConditioner}
62
- setCharacteristics={jest.fn()}
62
+ setCharacteristics={mockedSetCharacteristics}
63
63
  {...contextProps}
64
64
  />
65
65
  ),
@@ -75,18 +75,26 @@ jest.mock('@shopgate/pwa-common/context', () => ({
75
75
  }));
76
76
 
77
77
  describe('components/ProductCharacteristics', () => {
78
+ beforeEach(() => {
79
+ jest.clearAllMocks();
80
+ });
81
+
78
82
  it('should render', () => {
79
- const component = mount((
80
- <ProductCharacteristics render={jest.fn()} />
83
+ const renderer = jest.fn(({ id, label }) => <div key={id}>{label}</div>);
84
+
85
+ const { container } = render((
86
+ <ProductCharacteristics render={renderer} />
81
87
  ));
82
88
 
83
- expect(component).toMatchSnapshot();
89
+ expect(container).toHaveTextContent('ColorSize');
90
+ expect(mockedSetCharacteristics).toHaveBeenCalledTimes(1);
91
+ expect(mockedSetCharacteristics).toHaveBeenCalledWith({});
84
92
  });
85
93
 
86
94
  it('should call render prop', () => {
87
95
  const renderer = jest.fn();
88
96
 
89
- mount((
97
+ render((
90
98
  <ProductCharacteristics render={renderer} />
91
99
  ));
92
100
 
@@ -1,5 +1,4 @@
1
- import React from 'react';
2
- import { mount } from 'enzyme';
1
+ import { render, screen } from '@testing-library/react';
3
2
  import withHistoryActions from './withHistoryActions';
4
3
 
5
4
  const mockedAction = jest.fn();
@@ -16,19 +15,23 @@ jest.mock('react-redux', () => ({
16
15
 
17
16
  describe('connectors/withHistoryActions', () => {
18
17
  // eslint-disable-next-line react/prop-types, require-jsdoc
19
- const TestedComponent = props => <div>Other prop: {props.foo}</div>;
18
+ const TestedComponent = jest.fn(props => <div>Other prop: {props.foo}</div>);
20
19
  const ConnectedComponent = withHistoryActions(TestedComponent);
21
- let component;
22
- let props;
20
+
21
+ const renderConnected = () => {
22
+ render(<ConnectedComponent foo="bar" />);
23
+ return TestedComponent.mock.calls[0][0];
24
+ };
23
25
 
24
26
  beforeEach(() => {
25
27
  jest.clearAllMocks();
26
28
  });
27
29
 
28
30
  it('should render component with specified props', () => {
29
- component = mount(<ConnectedComponent foo="bar" />);
30
- props = component.find('TestedComponent').props();
31
+ const props = renderConnected();
31
32
 
33
+ expect(screen.getByText('Other prop: bar')).toBeInTheDocument();
34
+ expect(Object.keys(props).sort()).toEqual(['foo', 'historyPop', 'historyPush', 'historyReplace']);
32
35
  expect(typeof props.historyPop).toBe('function');
33
36
  expect(typeof props.historyPush).toBe('function');
34
37
  expect(typeof props.historyReplace).toBe('function');
@@ -41,6 +44,7 @@ describe('connectors/withHistoryActions', () => {
41
44
  actions.forEach((action) => {
42
45
  it(`should call ${action}`, () => {
43
46
  const pathname = 'PATHNAME';
47
+ const props = renderConnected();
44
48
  if (action === 'historyPop') {
45
49
  props[action]();
46
50
  expect(mockedAction).toHaveBeenCalledWith(action);
@@ -56,6 +60,7 @@ describe('connectors/withHistoryActions', () => {
56
60
  const options = {
57
61
  state: {},
58
62
  };
63
+ const props = renderConnected();
59
64
  if (action === 'historyPop') {
60
65
  props[action]();
61
66
  expect(mockedAction).toHaveBeenCalledWith(action);
@@ -1,5 +1,4 @@
1
- import React from 'react';
2
- import { mount } from 'enzyme';
1
+ import { render, screen } from '@testing-library/react';
3
2
  import withPageProductId from './withPageProductId';
4
3
 
5
4
  let mockedProductId;
@@ -34,14 +33,15 @@ describe('connectors/withPageProductId', () => {
34
33
  });
35
34
 
36
35
  // eslint-disable-next-line react/prop-types, require-jsdoc
37
- const MockedComponent = props => <div>{props.productId}</div>;
36
+ const MockedComponent = jest.fn(props => <div>Product: {String(props.productId)}</div>);
38
37
 
39
38
  it('should render with productId', () => {
40
39
  mockedProductId = '31323334';
41
40
  const Component = withPageProductId(MockedComponent);
42
41
 
43
- const component = mount(<Component otherProp={1} />);
44
- expect(component.find('MockedComponent').props()).toEqual({
42
+ render(<Component otherProp={1} />);
43
+ expect(screen.getByText('Product: 1234')).toBeInTheDocument();
44
+ expect(MockedComponent.mock.lastCall[0]).toEqual({
45
45
  productId: '1234',
46
46
  otherProp: 1,
47
47
  });
@@ -51,8 +51,9 @@ describe('connectors/withPageProductId', () => {
51
51
  mockedProductId = undefined;
52
52
  const Component = withPageProductId(MockedComponent);
53
53
 
54
- const component = mount(<Component otherProp={1} />);
55
- expect(component.find('MockedComponent').props()).toEqual({
54
+ render(<Component otherProp={1} />);
55
+ expect(screen.getByText('Product: null')).toBeInTheDocument();
56
+ expect(MockedComponent.mock.lastCall[0]).toEqual({
56
57
  productId: null,
57
58
  otherProp: 1,
58
59
  });
@@ -63,8 +64,9 @@ describe('connectors/withPageProductId', () => {
63
64
  mockedProductId = '123';
64
65
  const Component = withPageProductId(MockedComponent);
65
66
 
66
- const component = mount(<Component otherProp={1} />);
67
- expect(component.find('MockedComponent').props()).toEqual({
67
+ render(<Component otherProp={1} />);
68
+ expect(screen.getByText('Product: false')).toBeInTheDocument();
69
+ expect(MockedComponent.mock.lastCall[0]).toEqual({
68
70
  productId: false,
69
71
  otherProp: 1,
70
72
  });
@@ -1,5 +1,4 @@
1
- import React from 'react';
2
- import { mount } from 'enzyme';
1
+ import { render, screen } from '@testing-library/react';
3
2
  import withPageState from './withPageState';
4
3
 
5
4
  const isLoadingSpy = jest.fn();
@@ -10,7 +9,7 @@ const mockedIsLoading = (...args) => {
10
9
  };
11
10
 
12
11
  // eslint-disable-next-line react/prop-types, require-jsdoc
13
- const TestingComponent = props => <div>Other prop: {props.foo}</div>;
12
+ const TestingComponent = jest.fn(props => <div>Other prop: {props.foo}</div>);
14
13
 
15
14
  jest.mock('@shopgate/pwa-common/providers/', () => ({
16
15
  LoadingContext: {
@@ -44,9 +43,10 @@ jest.mock('@shopgate/pwa-common/context', () => ({
44
43
  describe('connectors/withPageState', () => {
45
44
  it('should render with specified props', () => {
46
45
  const ConnectedComponent = withPageState(TestingComponent);
47
- const component = mount(<ConnectedComponent foo="bar" />);
46
+ render(<ConnectedComponent foo="bar" />);
48
47
  expect(isLoadingSpy).toHaveBeenCalledWith('/foo/bar');
49
- expect(component.find('TestingComponent').props()).toEqual({
48
+ expect(screen.getByText('Other prop: bar')).toBeInTheDocument();
49
+ expect(TestingComponent.mock.lastCall[0]).toEqual({
50
50
  isVisible: true,
51
51
  isLoading: true,
52
52
  foo: 'bar',
@@ -1,9 +1,8 @@
1
- import React from 'react';
2
- import { mount } from 'enzyme';
1
+ import { render, screen } from '@testing-library/react';
3
2
  import WithProductContext from './withProductContext';
4
3
 
5
4
  // eslint-disable-next-line react/prop-types, require-jsdoc
6
- const TestingComponent = props => <div>Other prop: {props.foo}</div>;
5
+ const TestingComponent = jest.fn(props => <div>Other prop: {props.foo}</div>);
7
6
 
8
7
  jest.mock('@shopgate/pwa-common/context', () => ({
9
8
  // eslint-disable-next-line react/prop-types
@@ -40,9 +39,10 @@ jest.mock('@shopgate/pwa-common/context', () => ({
40
39
  describe('connectors/withProductContext', () => {
41
40
  it('should render with specified props', () => {
42
41
  const ConnectedComponent = WithProductContext(TestingComponent);
43
- const component = mount(<ConnectedComponent foo="bar" />);
42
+ render(<ConnectedComponent foo="bar" />);
44
43
 
45
- expect(component.find('TestingComponent').props()).toEqual({
44
+ expect(screen.getByText('Other prop: bar')).toBeInTheDocument();
45
+ expect(TestingComponent.mock.lastCall[0]).toEqual({
46
46
  foo: 'bar',
47
47
  productContext: {
48
48
  options: {},
@@ -1,9 +1,8 @@
1
- import React from 'react';
2
- import { mount } from 'enzyme';
1
+ import { render, screen } from '@testing-library/react';
3
2
  import withThemeComponents from './withThemeComponents';
4
3
 
5
4
  // eslint-disable-next-line react/prop-types, require-jsdoc
6
- const TestingComponent = props => <div>Other prop: {props.foo}</div>;
5
+ const TestingComponent = jest.fn(props => <div>Other prop: {props.foo}</div>);
7
6
 
8
7
  jest.mock('@shopgate/pwa-common/context', () => ({
9
8
  // eslint-disable-next-line react/prop-types
@@ -29,11 +28,16 @@ jest.mock('@shopgate/pwa-common/context', () => ({
29
28
  describe('connectors/withThemeComponents', () => {
30
29
  it('should render with specified props', () => {
31
30
  const ConnectedComponent = withThemeComponents(TestingComponent);
32
- const component = mount(<ConnectedComponent foo="bar" />);
31
+ render(<ConnectedComponent foo="bar" />);
33
32
 
34
- expect(component.find('TestingComponent').prop('contexts')).toBeUndefined();
33
+ expect(screen.getByText('Other prop: bar')).toBeInTheDocument();
35
34
 
36
- expect(Object.keys(component.find('TestingComponent').props())).toMatchObject([
35
+ const [[props]] = TestingComponent.mock.calls;
36
+
37
+ expect(props.contexts).toBeUndefined();
38
+ expect(props.foo).toBe('bar');
39
+
40
+ expect(Object.keys(props)).toMatchObject([
37
41
  'AppBar',
38
42
  'Drawer',
39
43
  'View',
@@ -1,5 +1,4 @@
1
- import React from 'react';
2
- import { mount } from 'enzyme';
1
+ import { render, screen } from '@testing-library/react';
3
2
  import withUser from './withUser';
4
3
 
5
4
  let mockedMapStateToPropsSpy = jest.fn();
@@ -25,12 +24,22 @@ jest.mock('react-redux', () => ({
25
24
  }
26
25
  }));
27
26
  describe('/connectors/withUser', () => {
28
- const TestedComponent = props => <div>Test</div>;
27
+ const TestedComponent = jest.fn(() => <div>Test</div>);
28
+ let mapStateToProps;
29
+
30
+ beforeAll(() => {
31
+ const ConnectedComponent = withUser(TestedComponent);
32
+ render(<ConnectedComponent />).unmount();
33
+ [[mapStateToProps]] = mockedMapStateToPropsSpy.mock.calls;
34
+ TestedComponent.mockClear();
35
+ });
36
+
29
37
  it('should create component and pass external props', () => {
30
38
  const ConnectedComponent = withUser(TestedComponent);
31
- const component = mount(<ConnectedComponent foo="bar" />);
39
+ render(<ConnectedComponent foo="bar" />);
32
40
 
33
- expect(component.find('TestedComponent').props()).toEqual({
41
+ expect(screen.getByText('Test')).toBeInTheDocument();
42
+ expect(TestedComponent.mock.lastCall[0]).toEqual({
34
43
  user: {
35
44
  ...mockedMapStateToPropsResult.user,
36
45
  },
@@ -53,7 +62,6 @@ describe('/connectors/withUser', () => {
53
62
  },
54
63
  };
55
64
 
56
- const mapStateToProps = mockedMapStateToPropsSpy.mock.calls[0][0];
57
65
  expect(mapStateToProps(state).user).toEqual({
58
66
  isLoggedIn: true,
59
67
  id: 'foo',
@@ -72,7 +80,6 @@ describe('/connectors/withUser', () => {
72
80
  },
73
81
  };
74
82
 
75
- const mapStateToProps = mockedMapStateToPropsSpy.mock.calls[0][0];
76
83
  expect(mapStateToProps(state).user).toEqual({
77
84
  isLoggedIn: false,
78
85
  id: null,
@@ -88,7 +95,6 @@ describe('/connectors/withUser', () => {
88
95
  user: {},
89
96
  };
90
97
 
91
- const mapStateToProps = mockedMapStateToPropsSpy.mock.calls[0][0];
92
98
  expect(mapStateToProps(state).user).toEqual({
93
99
  isLoggedIn: false,
94
100
  id: null,
package/locales/en.json CHANGED
@@ -25,6 +25,14 @@
25
25
  "INVALID": "... invalid:",
26
26
  "VALID": "... theme configuration is valid"
27
27
  },
28
+ "plugins/ShopgateTypeCheckPlugin": {
29
+ "CHECKING": "Type checking {name} ...",
30
+ "ERRORS": "Type errors: {count}",
31
+ "NO_ERRORS": "No type errors",
32
+ "NO_TYPESCRIPT": "Type check skipped for {name}: TypeScript is not installed there",
33
+ "FAILED": "Type check of {name} could not be started: {message}",
34
+ "STOPPED": "Type check of {name} stopped unexpectedly ({reason}). Restart the frontend to check it again. Its last output:"
35
+ },
28
36
  "webpack.config": {
29
37
  "WEBPACK_PROGRESS": "building [{bar}] [{message}] {percent} ({elapsed} seconds)"
30
38
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shopgate/webpack",
3
- "version": "7.32.2-alpha.9",
3
+ "version": "7.33.0-beta.2",
4
4
  "description": "The webpack configuration for Shopgate's Engage.",
5
5
  "main": "webpack.config.js",
6
6
  "license": "Apache-2.0",