creevey 0.9.0 → 0.9.1

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.
Files changed (84) hide show
  1. package/dist/client/addon/components/Panel.d.ts +1 -1
  2. package/dist/client/addon/components/Panel.js +5 -2
  3. package/dist/client/addon/components/Panel.js.map +1 -1
  4. package/dist/client/addon/withCreevey.js +1 -1
  5. package/dist/client/addon/withCreevey.js.map +1 -1
  6. package/dist/client/shared/components/PageFooter/PageFooter.d.ts +1 -3
  7. package/dist/client/shared/components/PageFooter/PageFooter.js +3 -8
  8. package/dist/client/shared/components/PageFooter/PageFooter.js.map +1 -1
  9. package/dist/client/shared/components/PageFooter/Paging.d.ts +1 -1
  10. package/dist/client/shared/components/PageFooter/Paging.js +4 -21
  11. package/dist/client/shared/components/PageFooter/Paging.js.map +1 -1
  12. package/dist/client/shared/components/PageHeader/PageHeader.d.ts +2 -2
  13. package/dist/client/shared/components/PageHeader/PageHeader.js +17 -10
  14. package/dist/client/shared/components/PageHeader/PageHeader.js.map +1 -1
  15. package/dist/client/shared/components/ResultsPage.d.ts +8 -6
  16. package/dist/client/shared/components/ResultsPage.js +5 -13
  17. package/dist/client/shared/components/ResultsPage.js.map +1 -1
  18. package/dist/client/shared/creeveyClientApi.d.ts +1 -0
  19. package/dist/client/shared/creeveyClientApi.js +3 -0
  20. package/dist/client/shared/creeveyClientApi.js.map +1 -1
  21. package/dist/client/shared/helpers.d.ts +2 -1
  22. package/dist/client/shared/helpers.js +23 -8
  23. package/dist/client/shared/helpers.js.map +1 -1
  24. package/dist/client/web/CreeveyApp.js +45 -8
  25. package/dist/client/web/CreeveyApp.js.map +1 -1
  26. package/dist/client/web/CreeveyContext.d.ts +3 -0
  27. package/dist/client/web/CreeveyContext.js +28 -4
  28. package/dist/client/web/CreeveyContext.js.map +1 -1
  29. package/dist/client/web/CreeveyView/SideBar/Checkbox.d.ts +1 -1
  30. package/dist/client/web/CreeveyView/SideBar/Checkbox.js +5 -5
  31. package/dist/client/web/CreeveyView/SideBar/Checkbox.js.map +1 -1
  32. package/dist/client/web/CreeveyView/SideBar/SideBar.d.ts +2 -2
  33. package/dist/client/web/CreeveyView/SideBar/SideBar.js +23 -13
  34. package/dist/client/web/CreeveyView/SideBar/SideBar.js.map +1 -1
  35. package/dist/client/web/CreeveyView/SideBar/SideBarFooter.d.ts +1 -0
  36. package/dist/client/web/CreeveyView/SideBar/SideBarFooter.js +32 -0
  37. package/dist/client/web/CreeveyView/SideBar/SideBarFooter.js.map +1 -0
  38. package/dist/client/web/CreeveyView/SideBar/SideBarHeader.js +1 -1
  39. package/dist/client/web/CreeveyView/SideBar/SuiteLink.d.ts +8 -3
  40. package/dist/client/web/CreeveyView/SideBar/SuiteLink.js +38 -23
  41. package/dist/client/web/CreeveyView/SideBar/SuiteLink.js.map +1 -1
  42. package/dist/client/web/CreeveyView/SideBar/TestLink.js +6 -5
  43. package/dist/client/web/CreeveyView/SideBar/TestLink.js.map +1 -1
  44. package/dist/client/web/CreeveyView/SideBar/TestStatusIcon.js +13 -6
  45. package/dist/client/web/CreeveyView/SideBar/TestStatusIcon.js.map +1 -1
  46. package/dist/client/web/CreeveyView/SideBar/TestsStatus.d.ts +1 -1
  47. package/dist/client/web/CreeveyView/SideBar/TestsStatus.js +6 -4
  48. package/dist/client/web/CreeveyView/SideBar/TestsStatus.js.map +1 -1
  49. package/dist/client/web/main.js +8 -8
  50. package/dist/server/master/api.js +4 -0
  51. package/dist/server/master/api.js.map +1 -1
  52. package/dist/server/master/runner.d.ts +2 -0
  53. package/dist/server/master/runner.js +59 -9
  54. package/dist/server/master/runner.js.map +1 -1
  55. package/dist/server/selenium/browser.js +9 -6
  56. package/dist/server/selenium/browser.js.map +1 -1
  57. package/dist/server/worker/worker.js +1 -0
  58. package/dist/server/worker/worker.js.map +1 -1
  59. package/dist/types.d.ts +4 -2
  60. package/dist/types.js.map +1 -1
  61. package/package.json +2 -1
  62. package/src/client/addon/components/Panel.tsx +7 -3
  63. package/src/client/addon/withCreevey.ts +1 -1
  64. package/src/client/shared/components/PageFooter/PageFooter.tsx +2 -20
  65. package/src/client/shared/components/PageFooter/Paging.tsx +22 -37
  66. package/src/client/shared/components/PageHeader/PageHeader.tsx +20 -14
  67. package/src/client/shared/components/ResultsPage.tsx +18 -31
  68. package/src/client/shared/creeveyClientApi.ts +4 -0
  69. package/src/client/shared/helpers.ts +22 -8
  70. package/src/client/web/CreeveyApp.tsx +66 -13
  71. package/src/client/web/CreeveyContext.tsx +7 -1
  72. package/src/client/web/CreeveyView/SideBar/Checkbox.tsx +5 -5
  73. package/src/client/web/CreeveyView/SideBar/SideBar.tsx +29 -18
  74. package/src/client/web/CreeveyView/SideBar/SideBarFooter.tsx +38 -0
  75. package/src/client/web/CreeveyView/SideBar/SideBarHeader.tsx +1 -1
  76. package/src/client/web/CreeveyView/SideBar/SuiteLink.tsx +50 -31
  77. package/src/client/web/CreeveyView/SideBar/TestLink.tsx +8 -6
  78. package/src/client/web/CreeveyView/SideBar/TestStatusIcon.tsx +12 -6
  79. package/src/client/web/CreeveyView/SideBar/TestsStatus.tsx +7 -3
  80. package/src/server/master/api.ts +4 -0
  81. package/src/server/master/runner.ts +65 -9
  82. package/src/server/selenium/browser.ts +13 -10
  83. package/src/server/worker/worker.ts +1 -0
  84. package/src/types.ts +4 -3
@@ -0,0 +1,38 @@
1
+ import React from 'react';
2
+ import { styled, withTheme } from '@storybook/theming';
3
+ import { Button, Icons } from '@storybook/components';
4
+ import { useCreeveyContext } from '../../CreeveyContext.js';
5
+
6
+ const Sticky = withTheme(
7
+ styled.div(({ theme }) => ({
8
+ padding: '24px 16px 8px 16px',
9
+ background: theme.background.content,
10
+ height: '50px',
11
+ zIndex: 5,
12
+ position: 'sticky',
13
+ bottom: '0',
14
+ })),
15
+ );
16
+
17
+ const Container = styled.div({
18
+ display: 'flex',
19
+ justifyContent: 'space-between',
20
+ });
21
+
22
+ export function SideBarFooter(): JSX.Element {
23
+ const { onApproveAll, onImageApprove } = useCreeveyContext();
24
+
25
+ return (
26
+ <Sticky>
27
+ <Container>
28
+ <Button secondary onClick={onImageApprove} disabled={!onImageApprove} style={{ paddingRight: 8 }}>
29
+ Approve
30
+ <Icons icon="arrowright" style={{ paddingLeft: 4 }} />
31
+ </Button>
32
+ <Button secondary outline onClick={onApproveAll}>
33
+ Approve all
34
+ </Button>
35
+ </Container>
36
+ </Sticky>
37
+ );
38
+ }
@@ -18,7 +18,7 @@ interface SideBarHeaderProps {
18
18
 
19
19
  const Sticky = withTheme(
20
20
  styled.div(({ theme }) => ({
21
- padding: '24px 32px 8px',
21
+ padding: '24px 36px 8px',
22
22
  background: theme.background.content,
23
23
  height: '130px',
24
24
  zIndex: 5,
@@ -14,49 +14,67 @@ export interface SuiteLinkProps {
14
14
  }
15
15
 
16
16
  export const Container = withTheme(
17
- styled.div<{ theme: Theme; disabled?: boolean }>(({ theme, disabled }) => ({
18
- position: 'relative',
19
- width: '100%',
20
- ...(disabled ? { color: theme.color.mediumdark, pointerEvents: 'none' } : {}),
21
- })),
17
+ styled.div<{ theme: Theme; disabled?: boolean; active?: boolean; focused?: boolean }>(
18
+ ({ theme, disabled, active, focused }) => ({
19
+ position: 'relative',
20
+ width: '100%',
21
+ height: '28px',
22
+ lineHeight: '20px',
23
+ display: 'flex',
24
+ background: active ? theme.color.secondary : focused ? theme.background.hoverable : 'none',
25
+ color: active ? theme.color.inverseText : 'inherit',
26
+ outline: focused ? `1px solid ${theme.color.ancillary}` : 'none',
27
+ ...(disabled ? { color: theme.color.mediumdark, pointerEvents: 'none' } : {}),
28
+
29
+ // NOTE There is no way to trigger hover from js, so we add `.hover` class for testing purpose
30
+ '&:hover, &.hover': active
31
+ ? {}
32
+ : {
33
+ background: theme.background.hoverable,
34
+ },
35
+ }),
36
+ ),
22
37
  );
23
38
 
24
39
  export const Button = withTheme(
25
- styled.button<{ theme: Theme; active?: boolean; focused?: boolean }>(({ theme, active, focused }) => ({
26
- width: '100%',
40
+ styled.button<{ theme: Theme; active?: boolean }>(({ theme, active }) => ({
41
+ flexGrow: 1,
27
42
  boxSizing: 'border-box',
28
43
  appearance: 'none',
29
- padding: '6px 36px',
30
- lineHeight: '20px',
44
+ padding: '4px 16px 4px 8px',
45
+ lineHeight: '18px',
31
46
  cursor: 'pointer',
32
47
  border: 'none',
33
48
  zIndex: 1,
34
49
  textAlign: 'left',
35
- background: active ? theme.color.secondary : focused ? theme.background.hoverable : 'none',
50
+ background: 'none',
51
+ outline: 'none',
36
52
  color: active ? theme.color.inverseText : 'inherit',
37
- outline: focused ? `1px solid ${theme.color.ancillary}` : 'none',
38
-
39
- // NOTE There is no way to trigger hover from js, so we add `.hover` class for testing purpose
40
- '&:hover, &.hover': active
41
- ? {}
42
- : {
43
- background: theme.background.hoverable,
44
- },
45
53
  })),
46
54
  );
47
55
 
48
56
  const ArrowIcon = styled(Icons)({
49
- paddingRight: '8px',
57
+ paddingRight: '4px',
50
58
  display: 'inline-block',
51
- width: '16px',
52
- height: '11px',
59
+ width: '12px',
60
+ height: '18px',
61
+ verticalAlign: 'unset',
53
62
  });
54
63
 
55
64
  export const SuiteContainer = styled.span<{ padding: number }>(({ padding }) => ({
56
65
  paddingLeft: padding,
57
66
  whiteSpace: 'normal',
67
+ display: 'grid',
68
+ gridTemplateColumns: 'repeat(2, min-content) auto',
58
69
  }));
59
70
 
71
+ export const SuiteTitle = styled.span({
72
+ paddingLeft: '4px',
73
+ whiteSpace: 'nowrap',
74
+ overflowX: 'hidden',
75
+ textOverflow: 'ellipsis',
76
+ });
77
+
60
78
  export function SuiteLink({ title, suite, 'data-testid': dataTid }: SuiteLinkProps): JSX.Element {
61
79
  const { onSuiteOpen, onSuiteToggle } = useContext(CreeveyContext);
62
80
  const { sidebarFocusedItem, setSidebarFocusedItem } = useContext(KeyboardEventsContext);
@@ -70,6 +88,7 @@ export function SuiteLink({ title, suite, 'data-testid': dataTid }: SuiteLinkPro
70
88
  sidebarFocusedItem.every((x) => suite.path.includes(x)),
71
89
  [suite, sidebarFocusedItem],
72
90
  );
91
+
73
92
  useEffect(
74
93
  () => (suite.indeterminate ? checkboxRef.current?.setIndeterminate() : checkboxRef.current?.resetIndeterminate()),
75
94
  [suite.indeterminate],
@@ -95,16 +114,7 @@ export function SuiteLink({ title, suite, 'data-testid': dataTid }: SuiteLinkPro
95
114
  };
96
115
 
97
116
  return (
98
- <Container>
99
- <Button onClick={handleOpen} onFocus={handleFocus} data-testid={dataTid} focused={isSuiteFocused} ref={buttonRef}>
100
- <TestStatusIcon status={suite.status} skip={suite.skip} />
101
- <SuiteContainer padding={Math.max(48, (suite.path.length + 5) * 8)}>
102
- {isTest(suite) ||
103
- (Boolean(suite.path.length) &&
104
- (suite.opened ? <ArrowIcon icon="arrowdown" /> : <ArrowIcon icon="arrowright" />))}
105
- {title}
106
- </SuiteContainer>
107
- </Button>
117
+ <Container focused={isSuiteFocused}>
108
118
  <CheckboxContainer>
109
119
  <Checkbox
110
120
  ref={checkboxRef}
@@ -113,6 +123,15 @@ export function SuiteLink({ title, suite, 'data-testid': dataTid }: SuiteLinkPro
113
123
  onValueChange={handleCheck}
114
124
  />
115
125
  </CheckboxContainer>
126
+ <Button onClick={handleOpen} onFocus={handleFocus} data-testid={dataTid} ref={buttonRef}>
127
+ <SuiteContainer padding={(suite.path.length - 1) * 8}>
128
+ {isTest(suite) ||
129
+ (Boolean(suite.path.length) &&
130
+ (suite.opened ? <ArrowIcon icon="arrowdown" /> : <ArrowIcon icon="arrowright" />))}
131
+ <TestStatusIcon status={suite.status} skip={suite.skip} />
132
+ <SuiteTitle>{title}</SuiteTitle>
133
+ </SuiteContainer>
134
+ </Button>
116
135
  </Container>
117
136
  );
118
137
  }
@@ -4,7 +4,7 @@ import { TestStatusIcon } from './TestStatusIcon.js';
4
4
  import { CreeveyContext } from '../../CreeveyContext.js';
5
5
  import { SideBarContext } from './SideBar.js';
6
6
  import { KeyboardEventsContext } from '../../KeyboardEventsContext.js';
7
- import { Button, Container, SuiteContainer } from './SuiteLink.js';
7
+ import { Button, Container, SuiteContainer, SuiteTitle } from './SuiteLink.js';
8
8
  import { Checkbox, CheckboxContainer } from './Checkbox.js';
9
9
  import { getTestPath } from '../../../shared/helpers.js';
10
10
 
@@ -48,11 +48,7 @@ export function TestLink({ title, opened, test }: TestLinkProps): JSX.Element {
48
48
  }, [test, onOpenTest, setSidebarFocusedItem]);
49
49
 
50
50
  return (
51
- <Container disabled={emptyResults}>
52
- <Button onClick={handleOpen} active={opened} focused={isTestFocused} disabled={emptyResults} ref={buttonRef}>
53
- <TestStatusIcon inverted={opened} status={test.status} skip={test.skip} />
54
- <SuiteContainer padding={(testPath.length + 8) * 8}>{title}</SuiteContainer>
55
- </Button>
51
+ <Container disabled={emptyResults} active={opened} focused={isTestFocused}>
56
52
  {/* NOTE Little hack to allow click on checkbox and don't trigger Button click */}
57
53
  {/* We can use other approach, but checkbox has vertical-align: top */}
58
54
  <CheckboxContainer>
@@ -62,6 +58,12 @@ export function TestLink({ title, opened, test }: TestLinkProps): JSX.Element {
62
58
  onValueChange={handleCheck}
63
59
  />
64
60
  </CheckboxContainer>
61
+ <Button onClick={handleOpen} disabled={emptyResults} ref={buttonRef}>
62
+ <SuiteContainer padding={(testPath.length + 1) * 8}>
63
+ <TestStatusIcon inverted={opened} status={test.status} skip={test.skip} />
64
+ <SuiteTitle>{title}</SuiteTitle>
65
+ </SuiteContainer>
66
+ </Button>
65
67
  </Container>
66
68
  );
67
69
  }
@@ -11,21 +11,22 @@ export interface TestStatusIconProps {
11
11
  }
12
12
 
13
13
  const Container = styled.span({
14
- width: 10,
15
- height: 10,
14
+ width: '16px',
15
+ height: '13px',
16
16
  padding: 1,
17
17
  display: 'inline-block',
18
18
  });
19
19
 
20
20
  const Icon = styled(Icons)({
21
21
  position: 'relative',
22
- top: '1.5px',
22
+ top: '1px',
23
23
  verticalAlign: 'baseline',
24
24
  });
25
25
 
26
26
  const Spinner = styled(Loader)({
27
- top: '14px',
28
- left: '42px',
27
+ top: '12px',
28
+ left: 'unset',
29
+ marginLeft: '0px',
29
30
  });
30
31
 
31
32
  export const TestStatusIcon = withTheme(
@@ -40,6 +41,10 @@ export const TestStatusIcon = withTheme(
40
41
  icon = <Icon color={inverted ? theme.color.lightest : theme.color.green} icon="check" />;
41
42
  break;
42
43
  }
44
+ case 'approved': {
45
+ icon = <Icon color={inverted ? theme.color.lightest : theme.color.mediumdark} icon="thumbsup" />;
46
+ break;
47
+ }
43
48
  case 'running': {
44
49
  icon = <Spinner size={10} />;
45
50
  break;
@@ -49,7 +54,8 @@ export const TestStatusIcon = withTheme(
49
54
  break;
50
55
  }
51
56
  default: {
52
- if (skip) icon = <Icon color={inverted ? theme.color.lightest : undefined} icon="timer" />;
57
+ if (skip) icon = <Icon color={inverted ? theme.color.lightest : undefined} icon="alert" />;
58
+ else icon = <Icon color={inverted ? theme.color.lightest : undefined} icon="circlehollow" />;
53
59
  break;
54
60
  }
55
61
  }
@@ -53,7 +53,7 @@ export const TestsStatus = withTheme(
53
53
  successCount,
54
54
  failedCount,
55
55
  pendingCount,
56
- skippedCount,
56
+ approvedCount,
57
57
  onClickByStatus,
58
58
  theme,
59
59
  }: TestsStatusProps): JSX.Element => {
@@ -94,9 +94,13 @@ export const TestsStatus = withTheme(
94
94
  </Button>
95
95
  <Divider />
96
96
  {/* @ts-expect-error Fixed in https://github.com/storybookjs/storybook/pull/26623 */}
97
- <Button>
97
+ <Button
98
+ onClick={() => {
99
+ onClickByStatus('approved');
100
+ }}
101
+ >
98
102
  <IconContainer color={theme?.color.defaultText}>
99
- <Icons icon="timer" /> {skippedCount}
103
+ <Icons icon="thumbsup" /> {approvedCount}
100
104
  </IconContainer>
101
105
  </Button>
102
106
  </Container>
@@ -49,6 +49,10 @@ export default function creeveyApi(runner: Runner): CreeveyApi {
49
49
  void runner.approve(command.payload);
50
50
  return;
51
51
  }
52
+ case 'approveAll': {
53
+ void runner.approveAll();
54
+ return;
55
+ }
52
56
  }
53
57
  },
54
58
  };
@@ -45,6 +45,7 @@ export default class Runner extends EventEmitter {
45
45
  // TODO Handle 'retrying' status
46
46
  test.status = status == 'retrying' ? 'failed' : status;
47
47
  if (!result) {
48
+ // NOTE: Running status
48
49
  this.sendUpdate({ tests: { [id]: { id, browser, testName, storyPath, status: test.status, storyId } } });
49
50
  return;
50
51
  }
@@ -53,8 +54,23 @@ export default class Runner extends EventEmitter {
53
54
  }
54
55
  test.results.push(result);
55
56
 
57
+ if (status == 'failed') {
58
+ test.approved = null;
59
+ }
60
+
56
61
  this.sendUpdate({
57
- tests: { [id]: { id, browser, testName, storyPath, status: test.status, results: [result], storyId } },
62
+ tests: {
63
+ [id]: {
64
+ id,
65
+ browser,
66
+ testName,
67
+ storyPath,
68
+ status: test.status,
69
+ approved: test.approved,
70
+ results: [result],
71
+ storyId,
72
+ },
73
+ },
58
74
  });
59
75
 
60
76
  if (this.failFast && status == 'failed') this.stop();
@@ -161,6 +177,44 @@ export default class Runner extends EventEmitter {
161
177
  };
162
178
  }
163
179
 
180
+ private async copyImage(test: ServerTest, image: string, actual: string): Promise<void> {
181
+ const { browser, testName, storyPath } = test;
182
+ const restPath = [...storyPath, testName].filter(isDefined);
183
+ const testPath = path.join(...restPath, image == browser ? '' : browser);
184
+ const srcImagePath = path.join(this.reportDir, testPath, actual);
185
+ const dstImagePath = path.join(this.screenDir, testPath, `${image}.png`);
186
+ await mkdir(path.join(this.screenDir, testPath), { recursive: true });
187
+ await copyFile(srcImagePath, dstImagePath);
188
+ }
189
+
190
+ public async approveAll(): Promise<void> {
191
+ const updatedTests: NonNullable<CreeveyUpdate['tests']> = {};
192
+ for (const test of Object.values(this.tests)) {
193
+ if (!test?.results) continue;
194
+ const retry = test.results.length - 1;
195
+ const { images, status } = test.results.at(retry) ?? {};
196
+ if (!images || status != 'failed') continue;
197
+ for (const [name, image] of Object.entries(images)) {
198
+ if (!image) continue;
199
+ await this.copyImage(test, name, image.actual);
200
+
201
+ if (!test.approved) {
202
+ test.approved = {};
203
+ }
204
+ test.approved[name] = retry;
205
+
206
+ updatedTests[test.id] = {
207
+ id: test.id,
208
+ browser: test.browser,
209
+ storyPath: test.storyPath,
210
+ storyId: test.storyId,
211
+ approved: { [name]: retry },
212
+ };
213
+ }
214
+ }
215
+ this.sendUpdate({ tests: updatedTests });
216
+ }
217
+
164
218
  public async approve({ id, retry, image }: ApprovePayload): Promise<void> {
165
219
  const test = this.tests[id];
166
220
  if (!test?.results) return;
@@ -171,16 +225,18 @@ export default class Runner extends EventEmitter {
171
225
  if (!test.approved) {
172
226
  test.approved = {};
173
227
  }
174
- const { browser, testName, storyPath } = test;
175
- const restPath = [...storyPath, testName].filter(isDefined);
176
- const testPath = path.join(...restPath, image == browser ? '' : browser);
177
- const srcImagePath = path.join(this.reportDir, testPath, images.actual);
178
- const dstImagePath = path.join(this.screenDir, testPath, `${image}.png`);
179
- await mkdir(path.join(this.screenDir, testPath), { recursive: true });
180
- await copyFile(srcImagePath, dstImagePath);
228
+ const { browser, testName, storyPath, storyId } = test;
229
+
230
+ await this.copyImage(test, image, images.actual);
231
+
181
232
  test.approved[image] = retry;
233
+
234
+ if (Object.keys(result.images).every((name) => typeof test.approved?.[name] == 'number')) {
235
+ test.status = 'approved';
236
+ }
237
+
182
238
  this.sendUpdate({
183
- tests: { [id]: { id, browser, testName, storyPath, approved: { [image]: retry }, storyId: test.storyId } },
239
+ tests: { [id]: { id, browser, testName, storyPath, status: test.status, approved: { [image]: retry }, storyId } },
184
240
  });
185
241
  }
186
242
  private sendUpdate(data: CreeveyUpdate): void {
@@ -55,6 +55,7 @@ let browserName = '';
55
55
  let browser: WebDriver | null = null;
56
56
  // let context: UnPromise<ReturnType<typeof BrowsingContext>> | null = null;
57
57
  let creeveyServerHost: string | null = null;
58
+ let creeveyServerPort: number | null = null;
58
59
 
59
60
  function getSessionData(grid: string, sessionId = ''): Promise<Record<string, unknown>> {
60
61
  const gridUrl = new URL(grid);
@@ -520,11 +521,10 @@ async function openStorybookPage(
520
521
  }
521
522
  }
522
523
 
523
- async function resolveCreeveyHost(browser: WebDriver, port: number): Promise<string> {
524
- if (creeveyServerHost != null) return creeveyServerHost;
525
-
524
+ async function resolveCreeveyHost(browser: WebDriver, port: number): Promise<void> {
526
525
  const addresses = getAddresses();
527
526
 
527
+ creeveyServerPort = port;
528
528
  creeveyServerHost = await browser.executeAsyncScript(
529
529
  function (hosts: string[], port: number, callback: (host?: string | null) => void) {
530
530
  void Promise.all(
@@ -558,8 +558,6 @@ async function resolveCreeveyHost(browser: WebDriver, port: number): Promise<str
558
558
  );
559
559
 
560
560
  if (creeveyServerHost == null) throw new Error("Can't reach creevey server from a browser");
561
-
562
- return creeveyServerHost;
563
561
  }
564
562
 
565
563
  export async function loadStoriesFromBrowser(): Promise<StoriesRaw> {
@@ -690,8 +688,14 @@ export async function getBrowser(config: Config, options: Options & { browser: s
690
688
  await updateStorybookGlobals(browser, _storybookGlobals);
691
689
  }
692
690
 
693
- const creeveyHost = await resolveCreeveyHost(browser, options.port);
691
+ await resolveCreeveyHost(browser, options.port);
692
+
693
+ await updateBrowserGlobalVariables(browser);
694
+
695
+ return browser;
696
+ }
694
697
 
698
+ async function updateBrowserGlobalVariables(browser: WebDriver) {
695
699
  await browser.executeScript(
696
700
  function (workerId: number, creeveyHost: string, creeveyPort: number) {
697
701
  window.__CREEVEY_WORKER_ID__ = workerId;
@@ -699,11 +703,9 @@ export async function getBrowser(config: Config, options: Options & { browser: s
699
703
  window.__CREEVEY_SERVER_PORT__ = creeveyPort;
700
704
  },
701
705
  process.pid,
702
- creeveyHost,
703
- options.port,
706
+ creeveyServerHost,
707
+ creeveyServerPort,
704
708
  );
705
-
706
- return browser;
707
709
  }
708
710
 
709
711
  async function updateStoryArgs(browser: WebDriver, story: StoryInput, updatedArgs: Args): Promise<void> {
@@ -799,6 +801,7 @@ export async function switchStory(this: Context): Promise<void> {
799
801
  });
800
802
  });
801
803
 
804
+ await updateBrowserGlobalVariables(this.browser);
802
805
  await resetMousePosition(this.browser);
803
806
  const isCaptureCalled = await selectStory(this.browser, id, waitForReady);
804
807
 
@@ -208,6 +208,7 @@ export async function start(config: Config, options: Options & { browser: string
208
208
  retries = test.retries;
209
209
 
210
210
  mocha.grep(new RegExp(`^${testPath}$`));
211
+ mocha.unloadFiles();
211
212
  const runner = mocha.run(runHandler);
212
213
 
213
214
  // TODO How handle browser corruption?
package/src/types.ts CHANGED
@@ -323,7 +323,7 @@ export interface Images {
323
323
  error?: string;
324
324
  }
325
325
 
326
- export type TestStatus = 'unknown' | 'pending' | 'running' | 'failed' | 'success' | 'retrying';
326
+ export type TestStatus = 'unknown' | 'pending' | 'running' | 'failed' | 'approved' | 'success' | 'retrying';
327
327
 
328
328
  export interface TestResult {
329
329
  status: 'failed' | 'success';
@@ -350,7 +350,7 @@ export interface TestData extends TestMeta {
350
350
  retries?: number;
351
351
  status?: TestStatus;
352
352
  results?: TestResult[];
353
- approved?: Partial<Record<string, number>>;
353
+ approved?: Partial<Record<string, number>> | null;
354
354
  }
355
355
 
356
356
  export interface ServerTest extends TestData {
@@ -415,7 +415,8 @@ export type Request =
415
415
  | { type: 'status' }
416
416
  | { type: 'start'; payload: string[] }
417
417
  | { type: 'stop' }
418
- | { type: 'approve'; payload: ApprovePayload };
418
+ | { type: 'approve'; payload: ApprovePayload }
419
+ | { type: 'approveAll' };
419
420
 
420
421
  export type Response =
421
422
  | { type: 'status'; payload: CreeveyStatus }