{"id":27639859,"url":"https://github.com/estruyf/playwright-m365-helpers","last_synced_at":"2025-04-23T22:35:01.102Z","repository":{"id":259445967,"uuid":"878001054","full_name":"estruyf/playwright-m365-helpers","owner":"estruyf","description":"A set of helpers for creating E2E tests for your Microsoft 365 projects using Playwright","archived":false,"fork":false,"pushed_at":"2024-12-19T16:30:10.000Z","size":53,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-15T21:06:31.124Z","etag":null,"topics":["authentication","e2e","e2e-testing","microsoft","microsoft365","power-platform","testing"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/playwright-m365-helpers","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/estruyf.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-10-24T15:49:25.000Z","updated_at":"2025-04-11T11:36:19.000Z","dependencies_parsed_at":"2024-11-14T16:33:53.148Z","dependency_job_id":"1ed60340-ae77-46a1-aca7-0375ec86e984","html_url":"https://github.com/estruyf/playwright-m365-helpers","commit_stats":null,"previous_names":["estruyf/playwright-m365-helpers"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/estruyf%2Fplaywright-m365-helpers","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/estruyf%2Fplaywright-m365-helpers/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/estruyf%2Fplaywright-m365-helpers/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/estruyf%2Fplaywright-m365-helpers/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/estruyf","download_url":"https://codeload.github.com/estruyf/playwright-m365-helpers/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250528258,"owners_count":21445509,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authentication","e2e","e2e-testing","microsoft","microsoft365","power-platform","testing"],"created_at":"2025-04-23T22:34:55.827Z","updated_at":"2025-04-23T22:35:01.092Z","avatar_url":"https://github.com/estruyf.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Playwright helpers for Microsoft 365 projects\n\nThis repository contains a set of Playwright helpers for Microsoft 365 projects.\n\n## Installation\n\n```bash\nnpm i playwright-m365-helpers\n```\n\n## Usage\n\n### Login to Microsoft 365\n\nCreate a new `login.setup.ts` file in your `tests` folder and add the following code:\n\n```typescript\nimport { test as setup } from \"@playwright/test\";\nimport { login } from 'playwright-m365-helpers';\n\nconst AuthFile = \"playwright/.auth/user.json\";\n\nsetup(\"authenticate\", async ({ page }) =\u003e {\n  \n  await login(\n    page,\n    process.env.M365_PAGE_URL,\n    process.env.M365_USERNAME,\n    process.env.M365_PASSWORD,\n    process.env.M365_OTP_SECRET // Optional\n  );\n\n  await page.context().storageState({ path: AuthFile });\n});\n```\n\n\u003e [!NOTE]\n\u003e In case of using Time-based One-Time Password (TOTP) for two-factor authentication, you can provide the secret key as the fourth parameter.\n\u003e To know more about signing in with TOTP, check the [automating Microsoft 365 login with multi-factor authentication in Playwright tests](https://www.eliostruyf.com/automating-microsoft-365-login-mfa-playwright-tests/) article.\n\nCreate a new project in the `playwright.config.ts` file with the following code:\n\n```typescript\nimport { defineConfig } from \"@playwright/test\";\n\nexport default defineConfig({\n  ...\n  projects: [\n    {\n      name: \"setup\",\n      testMatch: /login.setup.ts/,\n    },\n    {\n      name: \"chromium\",\n      use: {\n        storageState: \"playwright/.auth/user.json\",\n      },\n      dependencies: [\"setup\"], // This will run the setup project before the chromium project\n    },\n  ],\n});\n```\n\n### Power Platform helpers\n\nThere are various helpers for Power Platform projects:\n\n#### Locators\n\n- `getAppFrame` - Get the iframe of the Power Platform app\n\n  ```typescript\n  import { getAppFrame } from 'playwright-m365-helpers';\n\n  test(\"Check if canvas is loaded\", async () =\u003e {\n    await getAppFrame(page);\n  });\n  ```\n\n- `getControlByName` - Get the control by name\n  \n  ```typescript\n  import { getAppFrame, getControlByName } from 'playwright-m365-helpers';\n\n  test(\"Check if control is loaded\", async () =\u003e {\n    const appFrame = await getAppFrame(page);\n    const control = getControlByName(appFrame, \"controlName\");\n    await expect(control).toBeVisible();\n  });\n  ```\n\n- `getControlPart` - Get the control by its part name\n  \n  ```typescript\n  import { getAppFrame, getControlPart } from 'playwright-m365-helpers';\n\n  test(\"Check if control part can be retrieved\", async () =\u003e {\n    const appFrame = await getAppFrame(page);\n    const galleryItems = getControlPart(appFrame, \"gallery-item\");\n    await expect(galleryItems).toHaveCount(2);\n  });\n  ```\n\n- `getButton` - Get the button by name\n\n  ```typescript\n  import { getAppFrame, getButton } from 'playwright-m365-helpers';\n\n  test(\"Check if button is loaded\", async () =\u003e {\n    const appFrame = await getAppFrame(page);\n    const button = getButton(appFrame, \"buttonName\");\n    await expect(button).toBeVisible();\n    await button.click();\n  });\n  ```\n\n- `getDropdown` - Get the dropdown by name\n\n  ```typescript\n  import { getAppFrame, getDropdown } from 'playwright-m365-helpers';\n\n  test(\"Check if dropdown is loaded\", async () =\u003e {\n    const appFrame = await getAppFrame(page);\n    const dropdown = getDropdown(appFrame, \"dropdownName\");\n    await expect(dropdown).toBeVisible();\n  });\n  ```\n\n- `selectDropdownOption` - Select the dropdown option by its value\n\n  ```typescript\n  import { getAppFrame, getDropdown, selectDropdownOption } from 'playwright-m365-helpers';\n\n  test(\"Check if dropdown option is selected\", async () =\u003e {\n    const appFrame = await getAppFrame(page);\n    const dropdown = getDropdown(appFrame, \"dropdownName\");\n    await selectDropdownOption(appFrame, dropdown, \"dropdown value\");\n    await expect(dropdown).toHaveText(/dropdown value/);\n  });\n  ```\n\n- `getGalleryItems` - Get the gallery items\n  \n  ```typescript\n  import { getAppFrame, getControlPart } from 'playwright-m365-helpers';\n\n  test(\"Check if we can retrieve the gallery items\", async () =\u003e {\n    const appFrame = await getAppFrame(page);\n    const gallery = getControlByName(appFrame, \"galleryName\");\n    const galleryItems = getGalleryItems(gallery);\n    await expect(galleryItems).toHaveCount(2);\n  });\n  ```\n\n- `getInput` - Get the input by name\n\n  ```typescript\n  import { getAppFrame, getInput } from 'playwright-m365-helpers';\n\n  test(\"Check if input is loaded\", async () =\u003e {\n    const appFrame = await getAppFrame(page);\n    // Single line input\n    const input = getInput(appFrame, \"inputName\");\n    await expect(input).toBeVisible();\n    await input.fill(\"Hello World\");\n\n    // Multi-line input\n    const multiLineInput = getInput(appFrame, \"multiLineInputName\", true);\n    await expect(multiLineInput).toBeVisible();\n    await multiLineInput.fill(\"Hello World\");\n  });\n  ```\n\n- `getLabel` - Get the label by name\n\n  ```typescript\n  import { getAppFrame, getLabel } from 'playwright-m365-helpers';\n\n  test(\"Check if label is loaded\", async () =\u003e {\n    const appFrame = await getAppFrame(page);\n    const input = getLabel(appFrame, \"labelName\");\n    await expect(input).toHaveText(/Label text/);\n  });\n  ```\n\n- `getRadio` - Get the radio by name\n\n  ```typescript\n  import { getAppFrame, getRadio } from 'playwright-m365-helpers';\n\n  test(\"Check if radio is loaded\", async () =\u003e {\n    const appFrame = await getAppFrame(page);\n    const radio = getRadio(appFrame, \"radioName\");\n    await expect(radio).toBeVisible();\n  });\n  ```\n\n- `selectRadioOption` - Select the radio option by its value\n\n  ```typescript\n  import { getAppFrame, getRadio, selectRadioOption } from 'playwright-m365-helpers';\n\n  test(\"Select a radio option\", async () =\u003e {\n    const appFrame = await getAppFrame(page);\n    const radio = getRadio(appFrame, \"radioName\");\n    await selectRadioOption(radio, \"radio value\");\n  });\n  ```\n\n- `getRadioOptions` - Get the radio option(s)\n\n  ```typescript\n  import { getAppFrame, getRadio, getRadioOptions, selectRadioOption } from 'playwright-m365-helpers';\n\n  test(\"Check if radio options are loaded\", async () =\u003e {\n    const appFrame = await getAppFrame(page);\n    const radio = getRadio(appFrame, \"radioName\");\n    await selectRadioOption(radio, \"radio value\");\n\n    const selectedOption = await getRadioOptions(frame, radio, true);\n    await expect(selectedOption).toHaveText(/radio value/);\n  });\n  ```\n\n- `getScreen` - Get the screen by name\n\n  ```typescript\n  import { getAppFrame, getScreen } from 'playwright-m365-helpers';\n\n  test(\"Check if screen is loaded\", async () =\u003e {\n    const appFrame = await getAppFrame(page);\n    const screen = getScreen(appFrame, \"screenName\");\n    await expect(screen).toBeVisible();\n  });\n  ```\n\n- `getToggle` - Get the toggle by name\n\n  ```typescript\n  import { getAppFrame, getToggle } from 'playwright-m365-helpers';\n\n  test(\"Check if toggle is loaded\", async () =\u003e {\n    const appFrame = await getAppFrame(page);\n\n    const toggle = getToggle(appFrame, \"toggleName\");\n    await expect(toggle).toBeVisible();\n    await toggle.click();\n    await expect(toggle).toHaveAttribute(\"aria-checked\", \"true\");\n  });\n  ```\n\n#### API helpers\n\nIn order to use the API helpers, you need to know the Power Platform connector ID. You can find this ID if you are going to your Power Platform connections page, and click on the connector you want to use. The connector ID is part of the URL.\n\n`https://make.powerapps.com/environments/\u003cenvironment\u003e/connections/\u003cconnector ID\u003e/details`\n\nExample:\n\nIn the following URL:\n\n`https://make.powerapps.com/environments/12345678-1234-1234-1234-123456789012/connections/shared_sharepointonline/4aee3a63496d4e3f998c3910ba712bf2/details`\n\nThe connector ID is `shared_sharepointonline/4aee3a63496d4e3f998c3910ba712bf2`.\n\nThe following API helpers are available:\n\n- `mockConnector` - Mock the Power Platform connector\n\n  ```typescript\n  import { mockConnector } from 'playwright-m365-helpers';\n\n  test(\"Mock the connector\", async () =\u003e {\n    // Mock the connector with a GET request\n    await mockConnector(page, \"connectorId\", \"connectorResponse\");\n\n    // Mock the connector its POST event + status code\n    await mockConnector(page, \"connectorId\", \"connectorResponse\", \"POST\", 201;\n  });\n  ```\n\n- `waitForConnectorRequest` - Wait for the connector request to be made\n\n  ```typescript\n  import { waitForConnectorRequest } from 'playwright-m365-helpers';\n\n  test(\"Wait for the connector request\", async () =\u003e {\n    // Wait for the connector GET request\n    await waitForConnectorRequest(page, \"connectorId\");\n\n    // Wait for the connector POST request\n    await waitForConnectorRequest(page, \"connectorId\", \"POST\");\n  });\n  ```\n\n- `waitForConnectorResponse` - Wait for the connector response to be received\n\n  ```typescript\n  import { waitForConnectorResponse } from 'playwright-m365-helpers';\n\n  test(\"Wait for the connector response\", async () =\u003e {\n    // Wait for the connector GET response\n    await waitForConnectorResponse(page, \"connectorId\");\n\n    // Wait for the connector POST response\n    await waitForConnectorResponse(page, \"connectorId\", \"POST\");\n  });\n  ```\n\n\u003cbr /\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://visitorbadge.io/status?path=https%3A%2F%2Fgithub.com%2Festruyf%2Fplaywright-m365-helpers\"\u003e\n    \u003cimg src=\"https://api.visitorbadge.io/api/visitors?path=https%3A%2F%2Fgithub.com%2Festruyf%2Fplaywright-m365-helpers\u0026countColor=%23263759\" height=\"25px\" alt=\"playwright-m365-helpers visitors\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n\u003cbr /\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://struyfconsulting.com\" title=\"Hire Elio Struyf via Struyf Consulting\" target=\"_blank\"\u003e\n    \u003cimg src=\"./assets/struyf-consulting.webp\" height=\"25px\" alt=\"Struyf Consulting Logo\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Festruyf%2Fplaywright-m365-helpers","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Festruyf%2Fplaywright-m365-helpers","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Festruyf%2Fplaywright-m365-helpers/lists"}