@dxos/react-ui 0.1.34 → 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.
- package/dist/lib/browser/chunk-5VRACIDE.mjs +10 -0
- package/dist/lib/browser/chunk-5VRACIDE.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +225 -174
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/testing/index.mjs +43 -0
- package/dist/lib/browser/testing/index.mjs.map +7 -0
- package/dist/types/src/components/InvitationList/InvitationListContainer.d.ts.map +1 -1
- package/dist/types/src/components/InvitationList/InvitationListItem.d.ts.map +1 -1
- package/dist/types/src/composites/JoinDialog/JoinDialog.stories.d.ts.map +1 -1
- package/dist/types/src/composites/Shell/ShellContext.d.ts.map +1 -1
- package/dist/types/src/panels/DevicesPanel/DevicesPanel.d.ts.map +1 -1
- package/dist/types/src/panels/JoinPanel/joinMachine.d.ts +5 -5
- package/dist/types/src/panels/JoinPanel/joinMachine.d.ts.map +1 -1
- package/dist/types/src/panels/JoinPanel/view-states/InvitationAccepted.d.ts +1 -1
- package/dist/types/src/panels/JoinPanel/view-states/InvitationAccepted.d.ts.map +1 -1
- package/dist/types/src/panels/JoinPanel/view-states/InvitationAuthenticator.d.ts +2 -2
- package/dist/types/src/panels/JoinPanel/view-states/InvitationAuthenticator.d.ts.map +1 -1
- package/dist/types/src/panels/JoinPanel/view-states/InvitationInput.d.ts +2 -2
- package/dist/types/src/panels/JoinPanel/view-states/InvitationInput.d.ts.map +1 -1
- package/dist/types/src/panels/JoinPanel/view-states/InvitationRescuer.d.ts +2 -2
- package/dist/types/src/panels/JoinPanel/view-states/InvitationRescuer.d.ts.map +1 -1
- package/dist/types/src/panels/SpacePanel/SpacePanel.d.ts.map +1 -1
- package/dist/types/src/playwright/invitations-manager.d.ts +8 -17
- package/dist/types/src/playwright/invitations-manager.d.ts.map +1 -1
- package/dist/types/src/testing/index.d.ts +2 -0
- package/dist/types/src/testing/index.d.ts.map +1 -0
- package/dist/types/src/testing/shell-manager.d.ts +16 -0
- package/dist/types/src/testing/shell-manager.d.ts.map +1 -0
- package/dist/types/src/util/invitationStatusValue.d.ts.map +1 -1
- package/package.json +25 -14
- package/src/components/InvitationList/InvitationList.tsx +2 -2
- package/src/components/InvitationList/InvitationListContainer.tsx +3 -2
- package/src/components/InvitationList/InvitationListItem.tsx +4 -8
- package/src/composites/JoinDialog/JoinDialog.stories.tsx +3 -12
- package/src/composites/Shell/Shell.tsx +1 -1
- package/src/composites/Shell/ShellContext.tsx +11 -8
- package/src/panels/DevicesPanel/DevicesPanel.tsx +3 -1
- package/src/panels/JoinPanel/JoinPanel.tsx +8 -8
- package/src/panels/JoinPanel/joinMachine.ts +108 -98
- package/src/panels/JoinPanel/view-states/InvitationAccepted.tsx +6 -6
- package/src/panels/JoinPanel/view-states/InvitationAuthenticator.tsx +14 -14
- package/src/panels/JoinPanel/view-states/InvitationInput.tsx +9 -9
- package/src/panels/JoinPanel/view-states/InvitationRescuer.tsx +10 -10
- package/src/panels/SpacePanel/SpacePanel.tsx +19 -4
- package/src/playwright/invitations-manager.ts +23 -78
- package/src/playwright/invitations.spec.ts +79 -117
- package/src/testing/index.ts +5 -0
- package/src/testing/shell-manager.ts +59 -0
- 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
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
105
|
+
await this.peer(id).getByTestId('invitations.create-space').click();
|
|
117
106
|
}
|
|
118
107
|
|
|
119
|
-
async createInvitation(id: number, type: 'device' | 'space', options?:
|
|
108
|
+
async createInvitation(id: number, type: 'device' | 'space', options?: Partial<Invitation>): Promise<string> {
|
|
120
109
|
if (!options) {
|
|
121
|
-
const peer = this.
|
|
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.
|
|
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
|
|
152
|
-
|
|
153
|
-
|
|
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
|
-
|
|
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.
|
|
210
|
-
this.
|
|
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 [
|
|
30
|
-
|
|
31
|
-
|
|
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(
|
|
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 [
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
await manager.
|
|
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 [
|
|
86
|
-
|
|
87
|
-
|
|
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(
|
|
106
|
-
await manager.resetInvitation(1);
|
|
107
|
-
await manager.invitationInputContinue(
|
|
108
|
-
const [
|
|
109
|
-
|
|
110
|
-
|
|
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
|
-
|
|
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(
|
|
131
|
-
const [
|
|
132
|
-
|
|
133
|
-
|
|
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 [
|
|
150
|
-
manager.
|
|
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 [
|
|
156
|
-
manager.
|
|
140
|
+
const [authCode2] = await Promise.all([
|
|
141
|
+
manager.getAuthCode(),
|
|
157
142
|
manager.acceptInvitation(2, 'device', invitation2)
|
|
158
143
|
]);
|
|
159
|
-
await manager.authenticateInvitation(
|
|
160
|
-
await manager.authenticateInvitation(
|
|
161
|
-
await manager.doneInvitation(
|
|
162
|
-
await manager.doneInvitation(
|
|
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 [
|
|
180
|
-
|
|
181
|
-
|
|
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(
|
|
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 [
|
|
214
|
-
|
|
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(
|
|
198
|
+
expect(await manager.authenticatorIsVisible('space', manager.peer(1))).to.be.true;
|
|
220
199
|
|
|
221
|
-
await manager.
|
|
222
|
-
await manager.authenticateInvitation(
|
|
223
|
-
await manager.doneInvitation(
|
|
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(
|
|
240
|
-
await manager.
|
|
241
|
-
await manager.authenticateInvitation(
|
|
242
|
-
await manager.
|
|
243
|
-
await manager.authenticateInvitation(
|
|
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(
|
|
226
|
+
await manager.resetInvitation(manager.peer(1));
|
|
227
|
+
await manager.invitationInputContinue('space', manager.peer(1));
|
|
249
228
|
|
|
250
|
-
const [
|
|
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(
|
|
256
|
-
await manager.doneInvitation(
|
|
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 [
|
|
276
|
-
|
|
277
|
-
|
|
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(
|
|
299
|
-
await manager.resetInvitation(1);
|
|
300
|
-
await manager.invitationInputContinue(
|
|
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 [
|
|
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(
|
|
308
|
-
await manager.doneInvitation(
|
|
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
|
-
|
|
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(
|
|
329
|
-
const [
|
|
330
|
-
|
|
331
|
-
|
|
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 [
|
|
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 [
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
await manager.
|
|
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,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.
|
|
20
|
-
[Invitation.State.
|
|
19
|
+
[Invitation.State.READY_FOR_AUTHENTICATION, 3],
|
|
20
|
+
[Invitation.State.AUTHENTICATING, 4],
|
|
21
|
+
[Invitation.State.SUCCESS, 5]
|
|
21
22
|
]);
|