@bigbinary/neeto-playwright-commons 3.2.0 → 3.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.cjs.js +21 -2
- package/index.cjs.js.map +1 -1
- package/index.d.ts +45 -6
- package/index.js +22 -3
- package/index.js.map +1 -1
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -31,6 +31,7 @@ interface ExecuteRecursivelyParams {
|
|
|
31
31
|
interface VerifyToastParams {
|
|
32
32
|
message: string;
|
|
33
33
|
timeout?: number;
|
|
34
|
+
toastCloseTimeout?: number;
|
|
34
35
|
closeAfterVerification: boolean;
|
|
35
36
|
toastType: "success" | "error";
|
|
36
37
|
customPageContext?: Page;
|
|
@@ -219,6 +220,8 @@ declare class CustomCommands {
|
|
|
219
220
|
*
|
|
220
221
|
* timeout(optional): Timeout in milliseconds to wait for the toast to appear. Default is 10_000.
|
|
221
222
|
*
|
|
223
|
+
* toastCloseTimeout(optional): Timeout in milliseconds to wait for the toast to disappear after closing. Default is 10_000.
|
|
224
|
+
*
|
|
222
225
|
* customPageContext(optional): Custom page context on which to verify the toast.
|
|
223
226
|
*
|
|
224
227
|
* @example
|
|
@@ -228,6 +231,7 @@ declare class CustomCommands {
|
|
|
228
231
|
* closeAfterVerification: false,
|
|
229
232
|
* toastType: "error",
|
|
230
233
|
* timeout: 20_000,
|
|
234
|
+
* toastCloseTimeout: 15_000,
|
|
231
235
|
* customPageContext: this.page,
|
|
232
236
|
* });
|
|
233
237
|
* @endexample
|
|
@@ -237,6 +241,7 @@ declare class CustomCommands {
|
|
|
237
241
|
toastType,
|
|
238
242
|
closeAfterVerification,
|
|
239
243
|
timeout,
|
|
244
|
+
toastCloseTimeout,
|
|
240
245
|
customPageContext
|
|
241
246
|
}?: Partial<VerifyToastParams>) => Promise<void>;
|
|
242
247
|
/**
|
|
@@ -998,6 +1003,8 @@ declare class SlackApi {
|
|
|
998
1003
|
fetchMessages: (channelId: string, unixTimestamp: number) => Promise<playwright_core.APIResponse | undefined>;
|
|
999
1004
|
createChannel: (channelName: string) => Promise<playwright_core.APIResponse | undefined>;
|
|
1000
1005
|
addUser: (channelId: string, userId: string) => Promise<playwright_core.APIResponse | undefined>;
|
|
1006
|
+
listChannels: () => Promise<playwright_core.APIResponse | undefined>;
|
|
1007
|
+
archiveChannel: (channelId: string) => Promise<playwright_core.APIResponse | undefined>;
|
|
1001
1008
|
mockChannelDeleted: (channelId: string) => Promise<playwright_core.APIResponse | undefined>;
|
|
1002
1009
|
}
|
|
1003
1010
|
declare class WebhookSiteApi {
|
|
@@ -2917,6 +2924,7 @@ declare class SlackPage extends IntegrationBase {
|
|
|
2917
2924
|
allowButton: Locator;
|
|
2918
2925
|
callbackUrl: string;
|
|
2919
2926
|
currentWorkspace: string;
|
|
2927
|
+
slackApi: SlackApi;
|
|
2920
2928
|
constructor({
|
|
2921
2929
|
page,
|
|
2922
2930
|
neetoPlaywrightUtilities,
|
|
@@ -3088,18 +3096,25 @@ declare class SlackPage extends IntegrationBase {
|
|
|
3088
3096
|
channelName,
|
|
3089
3097
|
kind
|
|
3090
3098
|
}: CreateNewSlackChannelParams) => Promise<void>;
|
|
3099
|
+
/**
|
|
3100
|
+
* @deprecated Use {@link SlackPage.archiveChannelViaAPI} instead. This flow
|
|
3101
|
+
* drives the Slack web UI to permanently delete a channel and is brittle;
|
|
3102
|
+
* `archiveChannelViaAPI` archives via the Slack Web API (requires
|
|
3103
|
+
* `SLACK_BOT_TOKEN`).
|
|
3104
|
+
*/
|
|
3105
|
+
deleteSlackChannel: (channel: string) => Promise<void>;
|
|
3091
3106
|
/**
|
|
3092
3107
|
*
|
|
3093
|
-
*
|
|
3108
|
+
* Archives a Slack channel by name using the Slack Web API (conversations.list then conversations.archive). Requires SLACK_BOT_TOKEN with scopes that allow listing and archiving channels. Does not drive the Slack web UI; use when tests only need the channel removed or archived on the workspace.
|
|
3094
3109
|
*
|
|
3095
|
-
* channel:
|
|
3110
|
+
* channel: Channel name to archive.
|
|
3096
3111
|
*
|
|
3097
3112
|
* @example
|
|
3098
3113
|
*
|
|
3099
|
-
* await slackPage.
|
|
3114
|
+
* await slackPage.archiveChannelViaAPI("temp-test-channel");
|
|
3100
3115
|
* @endexample
|
|
3101
3116
|
*/
|
|
3102
|
-
|
|
3117
|
+
archiveChannelViaAPI: (name: string) => Promise<void>;
|
|
3103
3118
|
}
|
|
3104
3119
|
interface WebhooksPageParams {
|
|
3105
3120
|
page: Page;
|
|
@@ -4547,8 +4562,32 @@ declare class OrganizationPage {
|
|
|
4547
4562
|
page: Page;
|
|
4548
4563
|
neetoPlaywrightUtilities: CustomCommands;
|
|
4549
4564
|
constructor(page: Page, neetoPlaywrightUtilities: CustomCommands);
|
|
4550
|
-
|
|
4551
|
-
|
|
4565
|
+
/**
|
|
4566
|
+
*
|
|
4567
|
+
* Waits for the page to load, fills the OTP field, and waits until the OTP input is hidden (up to 35s), indicating the code was accepted.
|
|
4568
|
+
*
|
|
4569
|
+
* otp (optional): One-time password to enter. Defaults to a random 6-digit string.
|
|
4570
|
+
*
|
|
4571
|
+
* @example
|
|
4572
|
+
*
|
|
4573
|
+
* await organizationPage.fillOTP();
|
|
4574
|
+
* // OR
|
|
4575
|
+
* await organizationPage.fillOTP("123456");
|
|
4576
|
+
* @endexample
|
|
4577
|
+
*/
|
|
4578
|
+
fillOTP: (otp?: string) => Promise<void>;
|
|
4579
|
+
/**
|
|
4580
|
+
*
|
|
4581
|
+
* Waits for the page to load, fills the signup email field, clicks submit, and waits until the submit button is hidden (up to 35s). Use this as the first step when driving the email-based signup flow before entering an OTP.
|
|
4582
|
+
*
|
|
4583
|
+
* email: Address to enter in the signup email field.
|
|
4584
|
+
*
|
|
4585
|
+
* @example
|
|
4586
|
+
*
|
|
4587
|
+
* await organizationPage.submitEmail("jane@example.com");
|
|
4588
|
+
* @endexample
|
|
4589
|
+
*/
|
|
4590
|
+
submitEmail: (email: string) => Promise<void>;
|
|
4552
4591
|
private dismissAuthenticatorSetupPromptIfPresent;
|
|
4553
4592
|
/**
|
|
4554
4593
|
*
|
package/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { keysToSnakeCase, isPresent, hyphenate, isNotPresent, humanize,
|
|
1
|
+
import { keysToSnakeCase, isPresent, hyphenate, isNotPresent, humanize, findBy, dynamicArray, truncate, isNotEmpty, isNotEqualDeep, randomPick } from '@bigbinary/neeto-cist';
|
|
2
2
|
import { faker } from '@faker-js/faker';
|
|
3
3
|
import * as fs$4 from 'fs';
|
|
4
4
|
import fs__default, { readFileSync, promises, existsSync, writeFileSync, unlinkSync, mkdirSync, rmSync, createWriteStream } from 'fs';
|
|
@@ -618,6 +618,8 @@ class SlackApi {
|
|
|
618
618
|
fetchMessages = (channelId, unixTimestamp) => this.apiRequest("history", { channel: channelId, oldest: unixTimestamp });
|
|
619
619
|
createChannel = (channelName) => this.apiRequest("create", { name: channelName });
|
|
620
620
|
addUser = (channelId, userId) => this.apiRequest("invite", { channel: channelId, users: userId });
|
|
621
|
+
listChannels = () => this.apiRequest("list", { exclude_archived: 1, limit: 1000 });
|
|
622
|
+
archiveChannel = (channelId) => this.apiRequest("archive", { channel: channelId });
|
|
621
623
|
mockChannelDeleted = (channelId) => this.neetoPlaywrightUtilities.apiRequest({
|
|
622
624
|
url: "/neeto_slack/api/v1/testing/webhooks",
|
|
623
625
|
method: "post",
|
|
@@ -6048,7 +6050,7 @@ class CustomCommands {
|
|
|
6048
6050
|
const startTime = Date.now();
|
|
6049
6051
|
return await this.recursiveMethod(callback, condition, timeout, startTime, 1);
|
|
6050
6052
|
};
|
|
6051
|
-
verifyToast = async ({ message = "", toastType = "success", closeAfterVerification = true, timeout = 10_000, customPageContext = this.page, } = {}) => {
|
|
6053
|
+
verifyToast = async ({ message = "", toastType = "success", closeAfterVerification = true, timeout = 10_000, toastCloseTimeout = 10_000, customPageContext = this.page, } = {}) => {
|
|
6052
6054
|
// React-toastify does not support adding data-* attributes to toast DOM elements: https://github.com/fkhadra/react-toastify/issues/1106
|
|
6053
6055
|
const toastrLocator = customPageContext
|
|
6054
6056
|
.locator(COMMON_SELECTORS.neetoUiToastr)
|
|
@@ -6069,7 +6071,9 @@ class CustomCommands {
|
|
|
6069
6071
|
await customPageContext.evaluate(button => {
|
|
6070
6072
|
button.dispatchEvent(new Event("click", { bubbles: true }));
|
|
6071
6073
|
}, buttonHandle);
|
|
6072
|
-
await expect(toastrCloseButton).toBeHidden({
|
|
6074
|
+
await expect(toastrCloseButton).toBeHidden({
|
|
6075
|
+
timeout: toastCloseTimeout,
|
|
6076
|
+
});
|
|
6073
6077
|
}
|
|
6074
6078
|
};
|
|
6075
6079
|
waitForPageLoad = async ({ visibilityTimeout = 35_000, customPageContext = this.page, waitForOption = "serial", } = {}) => {
|
|
@@ -119460,6 +119464,7 @@ class SlackPage extends IntegrationBase {
|
|
|
119460
119464
|
allowButton;
|
|
119461
119465
|
callbackUrl;
|
|
119462
119466
|
currentWorkspace;
|
|
119467
|
+
slackApi;
|
|
119463
119468
|
constructor({ page, neetoPlaywrightUtilities, integrationRouteIndex, }) {
|
|
119464
119469
|
super({
|
|
119465
119470
|
page,
|
|
@@ -119470,6 +119475,7 @@ class SlackPage extends IntegrationBase {
|
|
|
119470
119475
|
this.allowButton = this.page.getByRole("button", {
|
|
119471
119476
|
name: SLACK_WEB_TEXTS.allow,
|
|
119472
119477
|
});
|
|
119478
|
+
this.slackApi = new SlackApi(this.neetoPlaywrightUtilities);
|
|
119473
119479
|
}
|
|
119474
119480
|
setupCloseHandlers = async (slackWebappPage = this.page) => {
|
|
119475
119481
|
const slackWebappPageDataQa = getByDataQA(slackWebappPage);
|
|
@@ -119654,6 +119660,12 @@ class SlackPage extends IntegrationBase {
|
|
|
119654
119660
|
await nextButton.click();
|
|
119655
119661
|
await this.slackWebappPageDataQa(SLACK_DATA_QA_SELECTORS.inviteToWorkspaceSkipButton).click();
|
|
119656
119662
|
};
|
|
119663
|
+
/**
|
|
119664
|
+
* @deprecated Use {@link SlackPage.archiveChannelViaAPI} instead. This flow
|
|
119665
|
+
* drives the Slack web UI to permanently delete a channel and is brittle;
|
|
119666
|
+
* `archiveChannelViaAPI` archives via the Slack Web API (requires
|
|
119667
|
+
* `SLACK_BOT_TOKEN`).
|
|
119668
|
+
*/
|
|
119657
119669
|
deleteSlackChannel = async (channel) => {
|
|
119658
119670
|
const channelItem = this.slackWebappPage.locator(SLACK_SELECTORS.channelItems, { hasText: channel });
|
|
119659
119671
|
await channelItem.click({ button: "right" });
|
|
@@ -119674,6 +119686,12 @@ class SlackPage extends IntegrationBase {
|
|
|
119674
119686
|
.click();
|
|
119675
119687
|
await expect(channelItem).toBeHidden();
|
|
119676
119688
|
};
|
|
119689
|
+
archiveChannelViaAPI = async (name) => {
|
|
119690
|
+
const response = await this.slackApi.listChannels();
|
|
119691
|
+
const { channels } = (await response?.json());
|
|
119692
|
+
const channel = findBy({ name }, channels);
|
|
119693
|
+
channel?.id && (await this.slackApi.archiveChannel(channel.id));
|
|
119694
|
+
};
|
|
119677
119695
|
}
|
|
119678
119696
|
|
|
119679
119697
|
class WebhooksPage {
|
|
@@ -126725,6 +126743,7 @@ const definePlaywrightConfig = (overrides) => {
|
|
|
126725
126743
|
name: PROJECT_NAMES.productionHealth,
|
|
126726
126744
|
testDir: "./e2e/health",
|
|
126727
126745
|
testMatch: "production.health.ts",
|
|
126746
|
+
retries: IS_CI ? 3 : 0,
|
|
126728
126747
|
use: {
|
|
126729
126748
|
...devices["Desktop Chrome"],
|
|
126730
126749
|
baseURL: process.env.PLAYWRIGHT_PRODUCTION_BASE_URL,
|