-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathintegration.test.ts
More file actions
171 lines (149 loc) · 6.1 KB
/
integration.test.ts
File metadata and controls
171 lines (149 loc) · 6.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
import type { ElectronApplication, Page } from "@playwright/test";
import { _electron as electron, expect, test } from "@playwright/test";
import type { SignInOptions } from "./types.js";
import { loadConfig } from "./helpers/loadConfig.js";
import { TestHelper } from "./helpers/TestHelper.js";
import { RefreshTokenStore } from "../main/TokenStore.js";
import { getPrefixedClientId } from "../common/IpcChannelNames.js";
const { clientId, envPrefix, email, password } = loadConfig();
const signInOptions: SignInOptions = {
clientId,
email,
password,
envPrefix,
};
// Get the user data path that would be returned in app.getPath('userData') if ran in main electron process.
const getElectronUserDataPath = (): string | undefined => {
switch (process.platform) {
case "darwin": // For MacOS
return `${process.env.HOME}/Library/Application Support/Electron`;
case "win32": { // For Windows
const appData = process.env.APPDATA;
if (!appData)
throw new Error("APPDATA environment variable not set on Windows");
return `${appData}/Electron`;
}
case "linux": // For Linux
return undefined; // Linux uses the same path for both main and renderer processes, no need to manually resolve path.
default:
return process.cwd();
}
};
const userDataPath = getElectronUserDataPath();
let electronApp: ElectronApplication;
let electronPage: Page;
const testHelper = new TestHelper(signInOptions);
const tokenStores = [
new RefreshTokenStore(getTokenStoreFileName(), getTokenStoreKey(), userDataPath),
new RefreshTokenStore(
getTokenStoreFileName("prefixed"),
getTokenStoreKey(undefined, "prefixed"),
userDataPath,
),
];
function getTokenStoreKey(issuerUrl?: string, channelClientPrefix?: string): string {
const authority = new URL(issuerUrl ?? "https://ims.bentley.com");
if (envPrefix && !issuerUrl) {
authority.hostname = envPrefix + authority.hostname;
}
issuerUrl = authority.href.replace(/\/$/, "");
return `${getTokenStoreFileName(channelClientPrefix)}:${issuerUrl}`;
}
function getTokenStoreFileName(channelClientPrefix?: string): string {
const clientIdWithPrefix = getPrefixedClientId(clientId, channelClientPrefix);
return `iTwinJs_${clientIdWithPrefix}`;
}
async function getUrl(app: ElectronApplication): Promise<string> {
// evaluates in the context of the main process
// TODO: consider writing a helper to make this easier
return app.evaluate<string>(async ({ shell }) => {
return new Promise((resolve) => {
shell.openExternal = async (url: string) => {
return resolve(url);
};
});
});
}
test.beforeEach(async () => {
try {
await Promise.all(tokenStores.map(async (store) => store.delete()));
electronApp = await electron.launch({
args: ["./dist/integration-test/test-app/index.js"],
});
electronPage = await electronApp.firstWindow();
} catch {
}
});
test.afterEach(async () => {
await electronApp.close();
});
test("buttons exist", async () => {
const signInButton = electronPage.getByTestId("signIn");
const signOutButton = electronPage.getByTestId("signOut");
const getStatusButton = electronPage.getByTestId("getStatus");
await expect(signInButton).toBeVisible();
await expect(signOutButton).toBeVisible();
await expect(getStatusButton).toBeVisible();
});
test("sign in successful", async ({ browser }) => {
const page = await browser.newPage();
await testHelper.checkStatus(electronPage, false);
await testHelper.clickSignIn(electronPage);
const url = await getUrl(electronApp);
await testHelper.signIn(page, url);
await testHelper.checkStatus(electronPage, true);
await page.close();
});
test("sign out successful", async ({ browser }) => {
const page = await browser.newPage();
await testHelper.clickSignIn(electronPage);
await testHelper.signIn(page, await getUrl(electronApp));
await testHelper.checkStatus(electronPage, true);
await testHelper.clickSignOut(electronPage);
await testHelper.checkStatus(electronPage, false);
await page.close();
});
test("when scopes change, sign in is required", async ({ browser }) => {
const page = await browser.newPage();
await testHelper.clickSignIn(electronPage);
await testHelper.signIn(page, await getUrl(electronApp));
await testHelper.checkStatus(electronPage, true);
// Admittedly this is cheating: no user would interact
// with the tokenStore directly, but this is a tough
// case to test otherwise.
await tokenStores[0].load("itwin-platform realitydata:read");
await testHelper.checkStatus(electronPage, false);
});
test("handles multiple instances with different channelClientPrefix", async ({
browser,
}) => {
// Sign in with the default auth client
const page = await browser.newPage();
await testHelper.checkStatus(electronPage, false);
await testHelper.checkOtherStatus(electronPage, false);
await testHelper.clickSignIn(electronPage);
const url = await getUrl(electronApp);
await testHelper.signIn(page, url);
await page.close();
// only the default auth client should be signed in
await testHelper.checkStatus(electronPage, true);
await testHelper.checkOtherStatus(electronPage, false);
// Now sign in with the other auth client
const otherPage = await browser.newPage();
await testHelper.clickOtherSignIn(electronPage);
const otherUrl = await getUrl(electronApp);
await testHelper.signIn(otherPage, otherUrl);
await otherPage.close();
// both auth clients should be signed in
await testHelper.checkOtherStatus(electronPage, true);
await testHelper.checkStatus(electronPage, true);
// sign out the default auth client
await testHelper.clickSignOut(electronPage);
// the other auth client should still be signed in
await testHelper.checkStatus(electronPage, false);
await testHelper.checkOtherStatus(electronPage, true);
});