@dxos/react-ui 0.1.35 → 0.1.36-next.ef27157

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 (50) hide show
  1. package/dist/lib/browser/chunk-5VRACIDE.mjs +10 -0
  2. package/dist/lib/browser/chunk-5VRACIDE.mjs.map +7 -0
  3. package/dist/lib/browser/index.mjs +225 -174
  4. package/dist/lib/browser/index.mjs.map +3 -3
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/browser/testing/index.mjs +43 -0
  7. package/dist/lib/browser/testing/index.mjs.map +7 -0
  8. package/dist/types/src/components/InvitationList/InvitationListContainer.d.ts.map +1 -1
  9. package/dist/types/src/components/InvitationList/InvitationListItem.d.ts.map +1 -1
  10. package/dist/types/src/composites/JoinDialog/JoinDialog.stories.d.ts.map +1 -1
  11. package/dist/types/src/composites/Shell/ShellContext.d.ts.map +1 -1
  12. package/dist/types/src/panels/DevicesPanel/DevicesPanel.d.ts.map +1 -1
  13. package/dist/types/src/panels/JoinPanel/joinMachine.d.ts +5 -5
  14. package/dist/types/src/panels/JoinPanel/joinMachine.d.ts.map +1 -1
  15. package/dist/types/src/panels/JoinPanel/view-states/InvitationAccepted.d.ts +1 -1
  16. package/dist/types/src/panels/JoinPanel/view-states/InvitationAccepted.d.ts.map +1 -1
  17. package/dist/types/src/panels/JoinPanel/view-states/InvitationAuthenticator.d.ts +2 -2
  18. package/dist/types/src/panels/JoinPanel/view-states/InvitationAuthenticator.d.ts.map +1 -1
  19. package/dist/types/src/panels/JoinPanel/view-states/InvitationInput.d.ts +2 -2
  20. package/dist/types/src/panels/JoinPanel/view-states/InvitationInput.d.ts.map +1 -1
  21. package/dist/types/src/panels/JoinPanel/view-states/InvitationRescuer.d.ts +2 -2
  22. package/dist/types/src/panels/JoinPanel/view-states/InvitationRescuer.d.ts.map +1 -1
  23. package/dist/types/src/panels/SpacePanel/SpacePanel.d.ts.map +1 -1
  24. package/dist/types/src/playwright/invitations-manager.d.ts +8 -17
  25. package/dist/types/src/playwright/invitations-manager.d.ts.map +1 -1
  26. package/dist/types/src/testing/index.d.ts +2 -0
  27. package/dist/types/src/testing/index.d.ts.map +1 -0
  28. package/dist/types/src/testing/shell-manager.d.ts +16 -0
  29. package/dist/types/src/testing/shell-manager.d.ts.map +1 -0
  30. package/dist/types/src/util/invitationStatusValue.d.ts.map +1 -1
  31. package/package.json +25 -14
  32. package/src/components/InvitationList/InvitationList.tsx +2 -2
  33. package/src/components/InvitationList/InvitationListContainer.tsx +3 -2
  34. package/src/components/InvitationList/InvitationListItem.tsx +4 -8
  35. package/src/composites/JoinDialog/JoinDialog.stories.tsx +3 -12
  36. package/src/composites/Shell/Shell.tsx +1 -1
  37. package/src/composites/Shell/ShellContext.tsx +11 -8
  38. package/src/panels/DevicesPanel/DevicesPanel.tsx +3 -1
  39. package/src/panels/JoinPanel/JoinPanel.tsx +8 -8
  40. package/src/panels/JoinPanel/joinMachine.ts +108 -98
  41. package/src/panels/JoinPanel/view-states/InvitationAccepted.tsx +6 -6
  42. package/src/panels/JoinPanel/view-states/InvitationAuthenticator.tsx +14 -14
  43. package/src/panels/JoinPanel/view-states/InvitationInput.tsx +9 -9
  44. package/src/panels/JoinPanel/view-states/InvitationRescuer.tsx +10 -10
  45. package/src/panels/SpacePanel/SpacePanel.tsx +19 -4
  46. package/src/playwright/invitations-manager.ts +23 -78
  47. package/src/playwright/invitations.spec.ts +79 -117
  48. package/src/testing/index.ts +5 -0
  49. package/src/testing/shell-manager.ts +59 -0
  50. package/src/util/invitationStatusValue.ts +3 -2
@@ -3,28 +3,29 @@
3
3
  //
4
4
 
5
5
  import { expect } from 'chai';
6
- import type { Browser, ConsoleMessage, Page } from 'playwright';
6
+ import type { Browser, ConsoleMessage } from 'playwright';
7
7
  import waitForExpect from 'wait-for-expect';
8
8
 
9
9
  import { Trigger } from '@dxos/async';
10
- import type { InvitationsOptions } from '@dxos/client';
11
- import { ConnectionState } from '@dxos/protocols/proto/dxos/client/services';
10
+ import { ConnectionState, Invitation } from '@dxos/protocols/proto/dxos/client/services';
12
11
  import { setupPage } from '@dxos/test/playwright';
13
12
 
13
+ import { ShellManager } from '../testing';
14
+
14
15
  // TODO(wittjosiah): Factor out.
15
16
  // TODO(burdon): No hard-coding of ports; reconcile all DXOS tools ports.
16
17
  const storybookUrl = (storyId: string) => `http://localhost:9009/iframe.html?id=${storyId}&viewMode=story`;
17
18
 
18
19
  export type PanelType = number | 'identity' | 'devices' | 'spaces' | 'join';
19
20
 
20
- export class InvitationsManager {
21
- page!: Page;
22
-
21
+ export class InvitationsManager extends ShellManager {
23
22
  private _initialized = false;
24
23
  private _invitationCode = new Trigger<string>();
25
- private _authenticationCode = new Trigger<string>();
24
+ private _authCode = new Trigger<string>();
26
25
 
27
- constructor(private readonly _browser: Browser) {}
26
+ constructor(private readonly _browser: Browser) {
27
+ super();
28
+ }
28
29
 
29
30
  async init() {
30
31
  if (this._initialized) {
@@ -45,24 +46,12 @@ export class InvitationsManager {
45
46
 
46
47
  async getDisplayName(id: number) {
47
48
  // TODO(wittjosiah): Update id.
48
- return this._peer(id).getByTestId('identity-list-item').nth(0).textContent();
49
+ return this.peer(id).getByTestId('identity-list-item').nth(0).textContent();
49
50
  }
50
51
 
51
52
  async getSpaceName(id: number, nth: number) {
52
53
  // TODO(wittjosiah): Update id.
53
- return this._peer(id).getByTestId('space-list-item').nth(nth).textContent();
54
- }
55
-
56
- authenticatorIsVisible(id: number, type: 'device' | 'space') {
57
- // TODO(wittjosiah): Update id.
58
- return this._peer(id)
59
- .getByTestId(`${type === 'device' ? 'halo' : 'space'}-auth-code-input`)
60
- .isVisible();
61
- }
62
-
63
- invitationFailed(id: number) {
64
- // TODO(wittjosiah): Update id.
65
- return this._peer(id).getByTestId('invitation-rescuer-reset').isVisible();
54
+ return this.peer(id).getByTestId('space-list-item').nth(nth).textContent();
66
55
  }
67
56
 
68
57
  // Actions
@@ -77,7 +66,7 @@ export class InvitationsManager {
77
66
  }
78
67
 
79
68
  async openPanel(id: number, panel: PanelType) {
80
- const peer = this._peer(id);
69
+ const peer = this.peer(id);
81
70
 
82
71
  if (typeof panel === 'number') {
83
72
  // TODO(wittjosiah): Update id.
@@ -104,7 +93,7 @@ export class InvitationsManager {
104
93
  }
105
94
 
106
95
  async createIdentity(id: number) {
107
- const createIdentity = this._peer(id).getByTestId('invitations.create-identity');
96
+ const createIdentity = this.peer(id).getByTestId('invitations.create-identity');
108
97
  // TODO(wittjosiah): Clicking on buttons wrapped in tooltips is flaky in webkit playwright.
109
98
  await createIdentity.click();
110
99
  await waitForExpect(async () => {
@@ -113,12 +102,12 @@ export class InvitationsManager {
113
102
  }
114
103
 
115
104
  async createSpace(id: number) {
116
- await this._peer(id).getByTestId('invitations.create-space').click();
105
+ await this.peer(id).getByTestId('invitations.create-space').click();
117
106
  }
118
107
 
119
- async createInvitation(id: number, type: 'device' | 'space', options?: InvitationsOptions): Promise<string> {
108
+ async createInvitation(id: number, type: 'device' | 'space', options?: Partial<Invitation>): Promise<string> {
120
109
  if (!options) {
121
- const peer = this._peer(id);
110
+ const peer = this.peer(id);
122
111
  this._invitationCode = new Trigger<string>();
123
112
  await peer.getByTestId(`${type}s-panel.create-invitation`).click();
124
113
  return this._invitationCode.wait();
@@ -139,7 +128,7 @@ export class InvitationsManager {
139
128
  }
140
129
 
141
130
  async acceptInvitation(id: number, type: 'device' | 'space', invitation: string) {
142
- const peer = this._peer(id);
131
+ const peer = this.peer(id);
143
132
  // TODO(wittjosiah): Update ids.
144
133
  if (type === 'device') {
145
134
  await peer.getByTestId('join-identity').click();
@@ -148,56 +137,12 @@ export class InvitationsManager {
148
137
  await this.page.keyboard.press('Enter');
149
138
  }
150
139
 
151
- async cancelInvitation(id: number, type: 'device' | 'space', kind: 'host' | 'guest') {
152
- const peer = this._peer(id);
153
- if (kind === 'guest') {
154
- await peer.getByTestId(`${type === 'device' ? 'halo' : 'space'}-invitation-authenticator-cancel`).click();
155
- }
156
- }
157
-
158
- async invitationInputContinue(id: number, type: 'device' | 'space') {
159
- // TODO(wittjosiah): Update ids.
160
- await this._peer(id)
161
- .getByTestId(`${type === 'device' ? 'halo' : 'space'}-invitation-input-continue`)
162
- .click();
163
- }
164
-
165
- async getAuthenticationCode(): Promise<string> {
166
- this._authenticationCode = new Trigger<string>();
167
- return await this._authenticationCode.wait();
168
- }
169
-
170
- async authenticateInvitation(id: number, type: 'device' | 'space', authenticationCode: string) {
171
- const peer = this._peer(id);
172
- // TODO(wittjosiah): Update ids.
173
- await peer.getByTestId(`${type === 'device' ? 'halo' : 'space'}-auth-code-input`).type(authenticationCode);
174
- await peer.getByTestId(`${type === 'device' ? 'halo' : 'space'}-invitation-authenticator-next`).click();
175
- }
176
-
177
- async clearAuthenticationCode(id: number, type: 'device' | 'space') {
178
- const peer = this._peer(id);
179
- // TODO(wittjosiah): Update ids.
180
- await peer.getByTestId(`${type === 'device' ? 'halo' : 'space'}-auth-code-input`).fill('');
181
- await peer.getByTestId(`${type === 'device' ? 'halo' : 'space'}-auth-code-input`).focus();
182
- }
183
-
184
- async resetInvitation(id: number) {
185
- const peer = this._peer(id);
186
- // TODO(wittjosiah): Update ids.
187
- await peer.getByTestId('invitation-rescuer-reset').click();
188
- }
189
-
190
- // TODO(wittjosiah): Remove.
191
- async doneInvitation(id: number, type: 'device' | 'space') {
192
- const peer = this._peer(id);
193
- // TODO(wittjosiah): Update ids.
194
- await peer
195
- .getByTestId(type === 'device' ? 'halo-invitation-accepted-done' : 'space-invitation-accepted-done')
196
- .click();
140
+ async getAuthCode(): Promise<string> {
141
+ this._authCode = new Trigger<string>();
142
+ return await this._authCode.wait();
197
143
  }
198
144
 
199
- // TODO(wittjosiah): Peer manager?
200
- private _peer(id: number) {
145
+ peer(id: number) {
201
146
  return this.page.getByTestId(`peer-${id}`);
202
147
  }
203
148
 
@@ -206,8 +151,8 @@ export class InvitationsManager {
206
151
  const json = JSON.parse(message.text());
207
152
  if (json.invitationCode) {
208
153
  this._invitationCode.wake(json.invitationCode);
209
- } else if (json.authenticationCode) {
210
- this._authenticationCode.wake(json.authenticationCode);
154
+ } else if (json.authCode) {
155
+ this._authCode.wake(json.authCode);
211
156
  }
212
157
  } catch {}
213
158
  }
@@ -6,8 +6,7 @@ import { test } from '@playwright/test';
6
6
  import { expect } from 'chai';
7
7
 
8
8
  import { sleep } from '@dxos/async';
9
- import { ConnectionState } from '@dxos/protocols/proto/dxos/client/services';
10
- import { AuthMethod } from '@dxos/protocols/proto/dxos/halo/invitations';
9
+ import { ConnectionState, Invitation } from '@dxos/protocols/proto/dxos/client/services';
11
10
 
12
11
  import { InvitationsManager } from './invitations-manager';
13
12
 
@@ -26,12 +25,9 @@ test.describe('Invitations', () => {
26
25
  const invitation = await manager.createInvitation(0, 'device');
27
26
 
28
27
  await manager.openPanel(1, 'identity');
29
- const [authenticationCode] = await Promise.all([
30
- manager.getAuthenticationCode(),
31
- manager.acceptInvitation(1, 'device', invitation)
32
- ]);
33
- await manager.authenticateInvitation(1, 'device', authenticationCode);
34
- await manager.doneInvitation(1, 'device');
28
+ const [authCode] = await Promise.all([manager.getAuthCode(), manager.acceptInvitation(1, 'device', invitation)]);
29
+ await manager.authenticateInvitation('device', authCode, manager.peer(1));
30
+ await manager.doneInvitation('device', manager.peer(1));
35
31
 
36
32
  expect(await manager.getDisplayName(0)).to.equal(await manager.getDisplayName(1));
37
33
  });
@@ -40,11 +36,11 @@ test.describe('Invitations', () => {
40
36
  test.skip('no auth method', async () => {
41
37
  await manager.createIdentity(0);
42
38
  await manager.openPanel(0, 'devices');
43
- const invitation = await manager.createInvitation(0, 'device', { authMethod: AuthMethod.NONE });
39
+ const invitation = await manager.createInvitation(0, 'device', { authMethod: Invitation.AuthMethod.NONE });
44
40
 
45
41
  await manager.openPanel(1, 'identity');
46
42
  await manager.acceptInvitation(1, 'device', invitation);
47
- await manager.doneInvitation(1, 'device');
43
+ await manager.doneInvitation('device', manager.peer(1));
48
44
 
49
45
  expect(await manager.getDisplayName(0)).to.equal(await manager.getDisplayName(1));
50
46
  });
@@ -56,14 +52,11 @@ test.describe('Invitations', () => {
56
52
  const invitation = await manager.createInvitation(0, 'device');
57
53
 
58
54
  await manager.openPanel(1, 'identity');
59
- const [authenticationCode] = await Promise.all([
60
- manager.getAuthenticationCode(),
61
- manager.acceptInvitation(1, 'device', invitation)
62
- ]);
63
- await manager.authenticateInvitation(1, 'device', '000000');
64
- await manager.clearAuthenticationCode(1, 'device');
65
- await manager.authenticateInvitation(1, 'device', authenticationCode);
66
- await manager.doneInvitation(1, 'device');
55
+ const [authCode] = await Promise.all([manager.getAuthCode(), manager.acceptInvitation(1, 'device', invitation)]);
56
+ await manager.authenticateInvitation('device', '000000', manager.peer(1));
57
+ await manager.clearAuthCode('device', manager.peer(1));
58
+ await manager.authenticateInvitation('device', authCode, manager.peer(1));
59
+ await manager.doneInvitation('device', manager.peer(1));
67
60
 
68
61
  expect(await manager.getDisplayName(0)).to.equal(await manager.getDisplayName(1));
69
62
  });
@@ -82,12 +75,9 @@ test.describe('Invitations', () => {
82
75
 
83
76
  // TODO(wittjosiah): Retry here.
84
77
 
85
- const [authenticationCode] = await Promise.all([
86
- manager.getAuthenticationCode(),
87
- manager.acceptInvitation(1, 'device', invitation)
88
- ]);
89
- await manager.authenticateInvitation(1, 'device', authenticationCode);
90
- await manager.doneInvitation(1, 'device');
78
+ const [authCode] = await Promise.all([manager.getAuthCode(), manager.acceptInvitation(1, 'device', invitation)]);
79
+ await manager.authenticateInvitation('device', authCode, manager.peer(1));
80
+ await manager.doneInvitation('device', manager.peer(1));
91
81
 
92
82
  expect(await manager.getDisplayName(0)).to.equal(await manager.getDisplayName(1));
93
83
  });
@@ -102,20 +92,18 @@ test.describe('Invitations', () => {
102
92
 
103
93
  await manager.openPanel(1, 'identity');
104
94
  await manager.acceptInvitation(1, 'device', invitation);
105
- await manager.cancelInvitation(1, 'device', 'guest');
106
- await manager.resetInvitation(1);
107
- await manager.invitationInputContinue(1, 'device');
108
- const [authenticationCode] = await Promise.all([
109
- manager.getAuthenticationCode(),
110
- manager.clearAuthenticationCode(1, 'device')
111
- ]);
112
- await manager.authenticateInvitation(1, 'device', authenticationCode);
113
- await manager.doneInvitation(1, 'device');
95
+ await manager.cancelInvitation('device', 'guest', manager.peer(1));
96
+ await manager.resetInvitation(manager.peer(1));
97
+ await manager.invitationInputContinue('device', manager.peer(1));
98
+ const [authCode] = await Promise.all([manager.getAuthCode(), manager.clearAuthCode('device', manager.peer(1))]);
99
+ await manager.authenticateInvitation('device', authCode, manager.peer(1));
100
+ await manager.doneInvitation('device', manager.peer(1));
114
101
 
115
102
  expect(await manager.getDisplayName(0)).to.equal(await manager.getDisplayName(1));
116
103
  });
117
104
 
118
- test('recover from network failure during invitation', async () => {
105
+ // TODO(wittjosiah): Propagating network failure is flaky.
106
+ test.skip('recover from network failure during invitation', async () => {
119
107
  await manager.createIdentity(0);
120
108
  await manager.openPanel(0, 'devices');
121
109
  const invitation = await manager.createInvitation(0, 'device');
@@ -126,14 +114,11 @@ test.describe('Invitations', () => {
126
114
  await manager.setConnectionState(0, ConnectionState.OFFLINE);
127
115
  await sleep(100);
128
116
  await manager.setConnectionState(0, ConnectionState.ONLINE);
129
- await manager.resetInvitation(1);
130
- await manager.invitationInputContinue(1, 'device');
131
- const [authenticationCode] = await Promise.all([
132
- manager.getAuthenticationCode(),
133
- manager.clearAuthenticationCode(1, 'device')
134
- ]);
135
- await manager.authenticateInvitation(1, 'device', authenticationCode);
136
- await manager.doneInvitation(1, 'device');
117
+ await manager.resetInvitation(manager.peer(1));
118
+ await manager.invitationInputContinue('device', manager.peer(1));
119
+ const [authCode] = await Promise.all([manager.getAuthCode(), manager.clearAuthCode('device', manager.peer(1))]);
120
+ await manager.authenticateInvitation('device', authCode, manager.peer(1));
121
+ await manager.doneInvitation('device', manager.peer(1));
137
122
 
138
123
  expect(await manager.getDisplayName(0)).to.equal(await manager.getDisplayName(1));
139
124
  });
@@ -146,20 +131,20 @@ test.describe('Invitations', () => {
146
131
 
147
132
  await manager.openPanel(1, 'identity');
148
133
  await manager.openPanel(2, 'identity');
149
- const [authenticationCode1] = await Promise.all([
150
- manager.getAuthenticationCode(),
134
+ const [authCode1] = await Promise.all([
135
+ manager.getAuthCode(),
151
136
  manager.acceptInvitation(1, 'device', invitation1)
152
137
  ]);
153
138
  // Prevent auth code from being reused.
154
139
  await sleep(100);
155
- const [authenticationCode2] = await Promise.all([
156
- manager.getAuthenticationCode(),
140
+ const [authCode2] = await Promise.all([
141
+ manager.getAuthCode(),
157
142
  manager.acceptInvitation(2, 'device', invitation2)
158
143
  ]);
159
- await manager.authenticateInvitation(1, 'device', authenticationCode1);
160
- await manager.authenticateInvitation(2, 'device', authenticationCode2);
161
- await manager.doneInvitation(1, 'device');
162
- await manager.doneInvitation(2, 'device');
144
+ await manager.authenticateInvitation('device', authCode1, manager.peer(1));
145
+ await manager.authenticateInvitation('device', authCode2, manager.peer(2));
146
+ await manager.doneInvitation('device', manager.peer(1));
147
+ await manager.doneInvitation('device', manager.peer(2));
163
148
 
164
149
  expect(await manager.getDisplayName(0)).to.equal(await manager.getDisplayName(1));
165
150
  expect(await manager.getDisplayName(0)).to.equal(await manager.getDisplayName(2));
@@ -176,12 +161,9 @@ test.describe('Invitations', () => {
176
161
 
177
162
  await manager.createIdentity(1);
178
163
  await manager.openPanel(1, 'join');
179
- const [authenticationCode] = await Promise.all([
180
- manager.getAuthenticationCode(),
181
- manager.acceptInvitation(1, 'space', invitation)
182
- ]);
183
- await manager.authenticateInvitation(1, 'space', authenticationCode);
184
- await manager.doneInvitation(1, 'space');
164
+ const [authCode] = await Promise.all([manager.getAuthCode(), manager.acceptInvitation(1, 'space', invitation)]);
165
+ await manager.authenticateInvitation('space', authCode, manager.peer(1));
166
+ await manager.doneInvitation('space', manager.peer(1));
185
167
 
186
168
  await manager.openPanel(0, 'spaces');
187
169
  expect(await manager.getSpaceName(0, 0)).to.equal(await manager.getSpaceName(1, 0));
@@ -191,12 +173,12 @@ test.describe('Invitations', () => {
191
173
  await manager.createIdentity(0);
192
174
  await manager.createSpace(0);
193
175
  await manager.openPanel(0, 0);
194
- const invitation = await manager.createInvitation(0, 'space', { authMethod: AuthMethod.NONE });
176
+ const invitation = await manager.createInvitation(0, 'space', { authMethod: Invitation.AuthMethod.NONE });
195
177
 
196
178
  await manager.createIdentity(1);
197
179
  await manager.openPanel(1, 'join');
198
180
  await manager.acceptInvitation(1, 'space', invitation);
199
- await manager.doneInvitation(1, 'space');
181
+ await manager.doneInvitation('space', manager.peer(1));
200
182
 
201
183
  await manager.openPanel(0, 'spaces');
202
184
  expect(await manager.getSpaceName(0, 0)).to.equal(await manager.getSpaceName(1, 0));
@@ -210,17 +192,14 @@ test.describe('Invitations', () => {
210
192
 
211
193
  await manager.createIdentity(1);
212
194
  await manager.openPanel(1, 'join');
213
- const [authenticationCode] = await Promise.all([
214
- manager.getAuthenticationCode(),
215
- manager.acceptInvitation(1, 'space', invitation)
216
- ]);
217
- await manager.authenticateInvitation(1, 'space', '000000');
195
+ const [authCode] = await Promise.all([manager.getAuthCode(), manager.acceptInvitation(1, 'space', invitation)]);
196
+ await manager.authenticateInvitation('space', '000000', manager.peer(1));
218
197
 
219
- expect(await manager.authenticatorIsVisible(1, 'space')).to.be.true;
198
+ expect(await manager.authenticatorIsVisible('space', manager.peer(1))).to.be.true;
220
199
 
221
- await manager.clearAuthenticationCode(1, 'space');
222
- await manager.authenticateInvitation(1, 'space', authenticationCode);
223
- await manager.doneInvitation(1, 'space');
200
+ await manager.clearAuthCode('space', manager.peer(1));
201
+ await manager.authenticateInvitation('space', authCode, manager.peer(1));
202
+ await manager.doneInvitation('space', manager.peer(1));
224
203
 
225
204
  await manager.openPanel(0, 'spaces');
226
205
  expect(await manager.getSpaceName(0, 0)).to.equal(await manager.getSpaceName(1, 0));
@@ -236,24 +215,21 @@ test.describe('Invitations', () => {
236
215
  await manager.openPanel(1, 'join');
237
216
  await manager.acceptInvitation(1, 'space', invitation);
238
217
 
239
- await manager.authenticateInvitation(1, 'space', '000001');
240
- await manager.clearAuthenticationCode(1, 'space');
241
- await manager.authenticateInvitation(1, 'space', '000002');
242
- await manager.clearAuthenticationCode(1, 'space');
243
- await manager.authenticateInvitation(1, 'space', '000003');
218
+ await manager.authenticateInvitation('space', '000001', manager.peer(1));
219
+ await manager.clearAuthCode('space', manager.peer(1));
220
+ await manager.authenticateInvitation('space', '000002', manager.peer(1));
221
+ await manager.clearAuthCode('space', manager.peer(1));
222
+ await manager.authenticateInvitation('space', '000003', manager.peer(1));
244
223
 
245
- expect(await manager.invitationFailed(1)).to.be.true;
224
+ expect(await manager.invitationFailed(manager.peer(1))).to.be.true;
246
225
 
247
- await manager.resetInvitation(1);
248
- await manager.invitationInputContinue(1, 'space');
226
+ await manager.resetInvitation(manager.peer(1));
227
+ await manager.invitationInputContinue('space', manager.peer(1));
249
228
 
250
- const [authenticationCode] = await Promise.all([
251
- manager.getAuthenticationCode(),
252
- manager.clearAuthenticationCode(1, 'space')
253
- ]);
229
+ const [authCode] = await Promise.all([manager.getAuthCode(), manager.clearAuthCode('space', manager.peer(1))]);
254
230
 
255
- await manager.authenticateInvitation(1, 'space', authenticationCode);
256
- await manager.doneInvitation(1, 'space');
231
+ await manager.authenticateInvitation('space', authCode, manager.peer(1));
232
+ await manager.doneInvitation('space', manager.peer(1));
257
233
 
258
234
  await manager.openPanel(0, 'spaces');
259
235
  expect(await manager.getSpaceName(0, 0)).to.equal(await manager.getSpaceName(1, 0));
@@ -272,12 +248,9 @@ test.describe('Invitations', () => {
272
248
 
273
249
  // TODO(wittjosiah): Retry here.
274
250
 
275
- const [authenticationCode] = await Promise.all([
276
- manager.getAuthenticationCode(),
277
- manager.acceptInvitation(1, 'space', invitation)
278
- ]);
279
- await manager.authenticateInvitation(1, 'space', authenticationCode);
280
- await manager.doneInvitation(1, 'space');
251
+ const [authCode] = await Promise.all([manager.getAuthCode(), manager.acceptInvitation(1, 'space', invitation)]);
252
+ await manager.authenticateInvitation('space', authCode, manager.peer(1));
253
+ await manager.doneInvitation('space', manager.peer(1));
281
254
 
282
255
  await manager.openPanel(0, 'spaces');
283
256
  expect(await manager.getSpaceName(0, 0)).to.equal(await manager.getSpaceName(1, 0));
@@ -295,23 +268,21 @@ test.describe('Invitations', () => {
295
268
  await manager.createIdentity(1);
296
269
  await manager.openPanel(1, 'join');
297
270
  await manager.acceptInvitation(1, 'space', invitation);
298
- await manager.cancelInvitation(1, 'space', 'guest');
299
- await manager.resetInvitation(1);
300
- await manager.invitationInputContinue(1, 'space');
271
+ await manager.cancelInvitation('space', 'guest', manager.peer(1));
272
+ await manager.resetInvitation(manager.peer(1));
273
+ await manager.invitationInputContinue('space', manager.peer(1));
301
274
 
302
- const [authenticationCode] = await Promise.all([
303
- manager.getAuthenticationCode(),
304
- manager.clearAuthenticationCode(1, 'space')
305
- ]);
275
+ const [authCode] = await Promise.all([manager.getAuthCode(), manager.clearAuthCode('space', manager.peer(1))]);
306
276
 
307
- await manager.authenticateInvitation(1, 'space', authenticationCode);
308
- await manager.doneInvitation(1, 'space');
277
+ await manager.authenticateInvitation('space', authCode, manager.peer(1));
278
+ await manager.doneInvitation('space', manager.peer(1));
309
279
 
310
280
  await manager.openPanel(0, 'spaces');
311
281
  expect(await manager.getSpaceName(0, 0)).to.equal(await manager.getSpaceName(1, 0));
312
282
  });
313
283
 
314
- test('recover from network failure during invitation', async () => {
284
+ // TODO(wittjosiah): Propagating network failure is flaky.
285
+ test.skip('recover from network failure during invitation', async () => {
315
286
  await manager.createIdentity(0);
316
287
  await manager.createSpace(0);
317
288
  await manager.openPanel(0, 0);
@@ -324,14 +295,11 @@ test.describe('Invitations', () => {
324
295
  await manager.setConnectionState(0, ConnectionState.OFFLINE);
325
296
  await sleep(100);
326
297
  await manager.setConnectionState(0, ConnectionState.ONLINE);
327
- await manager.resetInvitation(1);
328
- await manager.invitationInputContinue(1, 'space');
329
- const [authenticationCode] = await Promise.all([
330
- manager.getAuthenticationCode(),
331
- manager.clearAuthenticationCode(1, 'space')
332
- ]);
333
- await manager.authenticateInvitation(1, 'space', authenticationCode);
334
- await manager.doneInvitation(1, 'space');
298
+ await manager.resetInvitation(manager.peer(1));
299
+ await manager.invitationInputContinue('space', manager.peer(1));
300
+ const [authCode] = await Promise.all([manager.getAuthCode(), manager.clearAuthCode('space', manager.peer(1))]);
301
+ await manager.authenticateInvitation('space', authCode, manager.peer(1));
302
+ await manager.doneInvitation('space', manager.peer(1));
335
303
 
336
304
  await manager.openPanel(0, 'spaces');
337
305
  expect(await manager.getSpaceName(0, 0)).to.equal(await manager.getSpaceName(1, 0));
@@ -348,20 +316,14 @@ test.describe('Invitations', () => {
348
316
  await manager.createIdentity(2);
349
317
  await manager.openPanel(1, 'join');
350
318
  await manager.openPanel(2, 'join');
351
- const [authenticationCode1] = await Promise.all([
352
- manager.getAuthenticationCode(),
353
- manager.acceptInvitation(1, 'space', invitation1)
354
- ]);
319
+ const [authCode1] = await Promise.all([manager.getAuthCode(), manager.acceptInvitation(1, 'space', invitation1)]);
355
320
  // Prevent auth code from being reused.
356
321
  await sleep(100);
357
- const [authenticationCode2] = await Promise.all([
358
- manager.getAuthenticationCode(),
359
- manager.acceptInvitation(2, 'space', invitation2)
360
- ]);
361
- await manager.authenticateInvitation(1, 'space', authenticationCode1);
362
- await manager.authenticateInvitation(2, 'space', authenticationCode2);
363
- await manager.doneInvitation(1, 'space');
364
- await manager.doneInvitation(2, 'space');
322
+ const [authCode2] = await Promise.all([manager.getAuthCode(), manager.acceptInvitation(2, 'space', invitation2)]);
323
+ await manager.authenticateInvitation('space', authCode1, manager.peer(1));
324
+ await manager.authenticateInvitation('space', authCode2, manager.peer(2));
325
+ await manager.doneInvitation('space', manager.peer(1));
326
+ await manager.doneInvitation('space', manager.peer(2));
365
327
 
366
328
  await manager.openPanel(0, 'spaces');
367
329
  expect(await manager.getSpaceName(0, 0)).to.equal(await manager.getSpaceName(1, 0));
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ export * from './shell-manager';
@@ -0,0 +1,59 @@
1
+ //
2
+ // Copyright 2023 DXOS.org
3
+ //
4
+
5
+ import type { Locator, Page, FrameLocator } from 'playwright';
6
+
7
+ type Scope = Locator | FrameLocator | Page;
8
+
9
+ export class ShellManager {
10
+ page!: Page;
11
+
12
+ authenticatorIsVisible(type: 'device' | 'space', scope?: Scope) {
13
+ return (scope || this.page).getByTestId(`${type === 'device' ? 'halo' : 'space'}-auth-code-input`).isVisible();
14
+ }
15
+
16
+ invitationFailed(scope?: Scope) {
17
+ return (scope || this.page).getByTestId('invitation-rescuer-reset').isVisible();
18
+ }
19
+
20
+ async inputInvitation(type: 'device' | 'space', invitation: string, scope?: Scope) {
21
+ await (scope || this.page).getByTestId(`${type === 'device' ? 'halo' : 'space'}-invitation-input`).type(invitation);
22
+ await this.page.keyboard.press('Enter');
23
+ }
24
+
25
+ async invitationInputContinue(type: 'device' | 'space', scope?: Scope) {
26
+ await (scope || this.page).getByTestId(`${type === 'device' ? 'halo' : 'space'}-invitation-input-continue`).click();
27
+ }
28
+
29
+ async cancelInvitation(type: 'device' | 'space', kind: 'host' | 'guest', scope?: Scope) {
30
+ if (kind === 'guest') {
31
+ await (scope || this.page)
32
+ .getByTestId(`${type === 'device' ? 'halo' : 'space'}-invitation-authenticator-cancel`)
33
+ .click();
34
+ }
35
+ }
36
+
37
+ async authenticateInvitation(type: 'device' | 'space', authCode: string, scope?: Scope) {
38
+ const peer = scope || this.page;
39
+ // TODO(wittjosiah): Update ids.
40
+ await peer.getByTestId(`${type === 'device' ? 'halo' : 'space'}-auth-code-input`).type(authCode);
41
+ await peer.getByTestId(`${type === 'device' ? 'halo' : 'space'}-invitation-authenticator-next`).click();
42
+ }
43
+
44
+ async clearAuthCode(type: 'device' | 'space', scope?: Scope) {
45
+ const peer = scope || this.page;
46
+ await peer.getByTestId(`${type === 'device' ? 'halo' : 'space'}-auth-code-input`).fill('');
47
+ await peer.getByTestId(`${type === 'device' ? 'halo' : 'space'}-auth-code-input`).focus();
48
+ }
49
+
50
+ async resetInvitation(scope?: Scope) {
51
+ await (scope || this.page).getByTestId('invitation-rescuer-reset').click();
52
+ }
53
+
54
+ async doneInvitation(type: 'device' | 'space', scope?: Scope) {
55
+ await (scope || this.page)
56
+ .getByTestId(type === 'device' ? 'halo-invitation-accepted-done' : 'space-invitation-accepted-done')
57
+ .click();
58
+ }
59
+ }
@@ -16,6 +16,7 @@ export const invitationStatusValue = new Map<Invitation.State, number>([
16
16
  [Invitation.State.INIT, 0],
17
17
  [Invitation.State.CONNECTING, 1],
18
18
  [Invitation.State.CONNECTED, 2],
19
- [Invitation.State.AUTHENTICATING, 3],
20
- [Invitation.State.SUCCESS, 4]
19
+ [Invitation.State.READY_FOR_AUTHENTICATION, 3],
20
+ [Invitation.State.AUTHENTICATING, 4],
21
+ [Invitation.State.SUCCESS, 5]
21
22
  ]);