├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ ├── feature_request.md
│ └── quota-increase-request.md
└── workflows
│ └── ADOIntegration.yml
├── .gitignore
├── LICENSE
├── README.md
├── SECURITY.md
├── SUPPORT.md
└── samples
├── .NET
├── .gitignore
├── MSTest
│ ├── .runsettings
│ ├── PlaywrightTestsMSTest.csproj
│ ├── README.md
│ └── Tests.cs
└── NUnit
│ ├── .github
│ └── workflows
│ │ └── dotnet.yml
│ ├── .runsettings
│ ├── BrowserTestWithArtifact.cs
│ ├── ContextTestWithArtifact.cs
│ ├── PageTestWithArtifact.cs
│ ├── PlaywrightServiceSetup.cs
│ ├── PlaywrightTestWithArtifact.cs
│ ├── PlaywrightTestsNUnit.csproj
│ ├── README.md
│ └── Tests.cs
└── get-started
├── .github
└── workflows
│ └── get-started.yml
├── .gitignore
├── README.md
├── azure-pipelines.yml
├── package-lock.json
├── package.json
├── playwright.config.ts
├── playwright.service.config.ts
└── tests
└── example.spec.ts
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: "[BUG]:[Describe your issue here]"
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Step 1 '...'
16 | 2. Step 2 '....'
17 | 3. Step 3 '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Setup information (please complete the following information):**
27 | - Azure Subscription Id:
28 | - Workspace Name:
29 | - Service trace Id (if available):
30 | - Log snippet (if available):
31 | - Browser on which tests are executed (if applicable):
32 | - Time range (in PST) when the issue was experienced:
33 | - Playwright Version:
34 | - Client machine OS:
35 | - OS requested on Service:
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: enhancement
6 | assignees: vvs11
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/quota-increase-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Quota increase request
3 | about: Contact the team to increase the quota
4 | title: Quota increase request
5 | labels: ''
6 | assignees: vvs11
7 |
8 | ---
9 |
10 | ## Quota Increase Request
11 |
12 | **Quota to Increase:**
13 |
14 |
15 | [Specify which quota you would like to increase]
16 |
17 |
18 | * [ ] Maximum number of workers for the workspace
19 | * [ ] Maximum number of workspaces per subscription
20 | * [ ] Throttling limits
21 | * [ ] Other
22 |
23 |
24 |
25 | **Business Justification:**
26 |
27 | [Please provide a detailed business justification for the quota extension. Explain why this increase is necessary for your project or use case.]
28 |
29 | **Requested New Quota Limit:**
30 |
31 | [Specify the new quota limit you are requesting. Please be specific about the quantity or value (e.g., 60 workers per workspace, 5 workspaces per subscription etc.).]
32 |
33 | **Additional Information:**
34 |
35 | [Include any additional information that may be relevant to your request, such as project deadlines, the impact of the quota increase on your work, etc.]
36 |
37 | **Setup Information:**
38 |
39 | - **Subscription ID:** [Your Azure subscription ID]
40 | - **Workspace ID:** [ID of the workspace where you want to request quota increase]
41 |
42 | **Disclaimer:**
43 |
44 | Please note that while we will do our best to accommodate your quota extension request, we may not be able to fulfill every request due to resource constraints. We will review your request and provide a response as soon as possible.
45 |
--------------------------------------------------------------------------------
/.github/workflows/ADOIntegration.yml:
--------------------------------------------------------------------------------
1 | name: Sync issue to Azure DevOps work item
2 |
3 | on:
4 | issues:
5 | types:
6 | [opened, edited, closed, reopened]
7 |
8 | issue_comment:
9 | types: [created, edited, deleted]
10 |
11 | jobs:
12 | alert:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: danhellem/github-actions-issue-to-work-item@master
16 | env:
17 | ado_token: "${{ secrets.ADO_PERSONAL_ACCESS_TOKEN }}"
18 | github_token: "${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}"
19 | ado_organization: "devdiv"
20 | ado_project: "OnlineServices"
21 | ado_area_path: "OnlineServices\\PlaywrightService"
22 | ado_iteration_path: "OnlineServices\\Dilithium\\CY24 Q2"
23 | ado_wit: "Issue"
24 | ado_new_state: "New"
25 | ado_active_state: "Active"
26 | ado_close_state: "Closed"
27 | ado_bypassrules: false
28 | log_level: 100
29 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Aa][Rr][Mm]/
27 | [Aa][Rr][Mm]64/
28 | bld/
29 | [Bb]in/
30 | [Oo]bj/
31 | [Ll]og/
32 | [Ll]ogs/
33 |
34 | # Visual Studio 2015/2017 cache/options directory
35 | .vs/
36 | # Uncomment if you have tasks that create the project's static files in wwwroot
37 | #wwwroot/
38 |
39 | # Visual Studio 2017 auto generated files
40 | Generated\ Files/
41 |
42 | # MSTest test Results
43 | [Tt]est[Rr]esult*/
44 | [Bb]uild[Ll]og.*
45 |
46 | # NUnit
47 | *.VisualState.xml
48 | TestResult.xml
49 | nunit-*.xml
50 |
51 | # Build Results of an ATL Project
52 | [Dd]ebugPS/
53 | [Rr]eleasePS/
54 | dlldata.c
55 |
56 | # Benchmark Results
57 | BenchmarkDotNet.Artifacts/
58 |
59 | # .NET Core
60 | project.lock.json
61 | project.fragment.lock.json
62 | artifacts/
63 |
64 | # StyleCop
65 | StyleCopReport.xml
66 |
67 | # Files built by Visual Studio
68 | *_i.c
69 | *_p.c
70 | *_h.h
71 | *.ilk
72 | *.meta
73 | *.obj
74 | *.iobj
75 | *.pch
76 | *.pdb
77 | *.ipdb
78 | *.pgc
79 | *.pgd
80 | *.rsp
81 | *.sbr
82 | *.tlb
83 | *.tli
84 | *.tlh
85 | *.tmp
86 | *.tmp_proj
87 | *_wpftmp.csproj
88 | *.log
89 | *.vspscc
90 | *.vssscc
91 | .builds
92 | *.pidb
93 | *.svclog
94 | *.scc
95 |
96 | # Chutzpah Test files
97 | _Chutzpah*
98 |
99 | # Visual C++ cache files
100 | ipch/
101 | *.aps
102 | *.ncb
103 | *.opendb
104 | *.opensdf
105 | *.sdf
106 | *.cachefile
107 | *.VC.db
108 | *.VC.VC.opendb
109 |
110 | # Visual Studio profiler
111 | *.psess
112 | *.vsp
113 | *.vspx
114 | *.sap
115 |
116 | # Visual Studio Trace Files
117 | *.e2e
118 |
119 | # TFS 2012 Local Workspace
120 | $tf/
121 |
122 | # Guidance Automation Toolkit
123 | *.gpState
124 |
125 | # ReSharper is a .NET coding add-in
126 | _ReSharper*/
127 | *.[Rr]e[Ss]harper
128 | *.DotSettings.user
129 |
130 | # TeamCity is a build add-in
131 | _TeamCity*
132 |
133 | # DotCover is a Code Coverage Tool
134 | *.dotCover
135 |
136 | # AxoCover is a Code Coverage Tool
137 | .axoCover/*
138 | !.axoCover/settings.json
139 |
140 | # Visual Studio code coverage results
141 | *.coverage
142 | *.coveragexml
143 |
144 | # NCrunch
145 | _NCrunch_*
146 | .*crunch*.local.xml
147 | nCrunchTemp_*
148 |
149 | # MightyMoose
150 | *.mm.*
151 | AutoTest.Net/
152 |
153 | # Web workbench (sass)
154 | .sass-cache/
155 |
156 | # Installshield output folder
157 | [Ee]xpress/
158 |
159 | # DocProject is a documentation generator add-in
160 | DocProject/buildhelp/
161 | DocProject/Help/*.HxT
162 | DocProject/Help/*.HxC
163 | DocProject/Help/*.hhc
164 | DocProject/Help/*.hhk
165 | DocProject/Help/*.hhp
166 | DocProject/Help/Html2
167 | DocProject/Help/html
168 |
169 | # Click-Once directory
170 | publish/
171 |
172 | # Publish Web Output
173 | *.[Pp]ublish.xml
174 | *.azurePubxml
175 | # Note: Comment the next line if you want to checkin your web deploy settings,
176 | # but database connection strings (with potential passwords) will be unencrypted
177 | *.pubxml
178 | *.publishproj
179 |
180 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
181 | # checkin your Azure Web App publish settings, but sensitive information contained
182 | # in these scripts will be unencrypted
183 | PublishScripts/
184 |
185 | # NuGet Packages
186 | *.nupkg
187 | # NuGet Symbol Packages
188 | *.snupkg
189 | # The packages folder can be ignored because of Package Restore
190 | **/[Pp]ackages/*
191 | # except build/, which is used as an MSBuild target.
192 | !**/[Pp]ackages/build/
193 | # Uncomment if necessary however generally it will be regenerated when needed
194 | #!**/[Pp]ackages/repositories.config
195 | # NuGet v3's project.json files produces more ignorable files
196 | *.nuget.props
197 | *.nuget.targets
198 |
199 | # Microsoft Azure Build Output
200 | csx/
201 | *.build.csdef
202 |
203 | # Microsoft Azure Emulator
204 | ecf/
205 | rcf/
206 |
207 | # Windows Store app package directories and files
208 | AppPackages/
209 | BundleArtifacts/
210 | Package.StoreAssociation.xml
211 | _pkginfo.txt
212 | *.appx
213 | *.appxbundle
214 | *.appxupload
215 |
216 | # Visual Studio cache files
217 | # files ending in .cache can be ignored
218 | *.[Cc]ache
219 | # but keep track of directories ending in .cache
220 | !?*.[Cc]ache/
221 |
222 | # Others
223 | ClientBin/
224 | ~$*
225 | *~
226 | *.dbmdl
227 | *.dbproj.schemaview
228 | *.jfm
229 | *.pfx
230 | *.publishsettings
231 | orleans.codegen.cs
232 |
233 | # Including strong name files can present a security risk
234 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
235 | #*.snk
236 |
237 | # Since there are multiple workflows, uncomment next line to ignore bower_components
238 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
239 | #bower_components/
240 |
241 | # RIA/Silverlight projects
242 | Generated_Code/
243 |
244 | # Backup & report files from converting an old project file
245 | # to a newer Visual Studio version. Backup files are not needed,
246 | # because we have git ;-)
247 | _UpgradeReport_Files/
248 | Backup*/
249 | UpgradeLog*.XML
250 | UpgradeLog*.htm
251 | ServiceFabricBackup/
252 | *.rptproj.bak
253 |
254 | # SQL Server files
255 | *.mdf
256 | *.ldf
257 | *.ndf
258 |
259 | # Business Intelligence projects
260 | *.rdl.data
261 | *.bim.layout
262 | *.bim_*.settings
263 | *.rptproj.rsuser
264 | *- [Bb]ackup.rdl
265 | *- [Bb]ackup ([0-9]).rdl
266 | *- [Bb]ackup ([0-9][0-9]).rdl
267 |
268 | # Microsoft Fakes
269 | FakesAssemblies/
270 |
271 | # GhostDoc plugin setting file
272 | *.GhostDoc.xml
273 |
274 | # Node.js Tools for Visual Studio
275 | .ntvs_analysis.dat
276 | node_modules/
277 |
278 | # Visual Studio 6 build log
279 | *.plg
280 |
281 | # Visual Studio 6 workspace options file
282 | *.opt
283 |
284 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
285 | *.vbw
286 |
287 | # Visual Studio LightSwitch build output
288 | **/*.HTMLClient/GeneratedArtifacts
289 | **/*.DesktopClient/GeneratedArtifacts
290 | **/*.DesktopClient/ModelManifest.xml
291 | **/*.Server/GeneratedArtifacts
292 | **/*.Server/ModelManifest.xml
293 | _Pvt_Extensions
294 |
295 | # Paket dependency manager
296 | .paket/paket.exe
297 | paket-files/
298 |
299 | # FAKE - F# Make
300 | .fake/
301 |
302 | # CodeRush personal settings
303 | .cr/personal
304 |
305 | # Python Tools for Visual Studio (PTVS)
306 | __pycache__/
307 | *.pyc
308 |
309 | # Cake - Uncomment if you are using it
310 | # tools/**
311 | # !tools/packages.config
312 |
313 | # Tabs Studio
314 | *.tss
315 |
316 | # Telerik's JustMock configuration file
317 | *.jmconfig
318 |
319 | # BizTalk build output
320 | *.btp.cs
321 | *.btm.cs
322 | *.odx.cs
323 | *.xsd.cs
324 |
325 | # OpenCover UI analysis results
326 | OpenCover/
327 |
328 | # Azure Stream Analytics local run output
329 | ASALocalRun/
330 |
331 | # MSBuild Binary and Structured Log
332 | *.binlog
333 |
334 | # NVidia Nsight GPU debugger configuration file
335 | *.nvuser
336 |
337 | # MFractors (Xamarin productivity tool) working folder
338 | .mfractor/
339 |
340 | # Local History for Visual Studio
341 | .localhistory/
342 |
343 | # BeatPulse healthcheck temp database
344 | healthchecksdb
345 |
346 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
347 | MigrationBackup/
348 |
349 | # Ionide (cross platform F# VS Code tools) working folder
350 | .ionide/
351 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Microsoft Corporation.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Microsoft Playwright Testing preview
2 |
3 | Microsoft Playwright Testing is a fully managed service that uses the cloud to enable you to run Playwright tests with much higher parallelization across different operating system-browser combinations simultaneously. Along with this, it enables you to publish test results and artifacts collected by Playwright to the service. This means faster test runs with broader scenario coverage, which helps speed up delivery of features without sacrificing quality.
4 |
5 | Ready to get started? Jump into our [quickstart guide](#get-started)!
6 |
7 | https://github.com/microsoft/playwright-testing-service/assets/12104064/29b969ec-7106-4407-a34a-4f04756d16f7
8 |
9 | ## Useful Links
10 | - [Quickstart: Run end-to-end tests at scale](https://aka.ms/mpt/quickstart)
11 | - [Quickstart: Set up continuous end-to-end testing across different browsers and operating systems](https://aka.ms/mpt/ci)
12 | - [Explore features and benefits](https://aka.ms/mpt/about)
13 | - [Documentation](https://aka.ms/mpt/docs)
14 | - [Pricing](https://aka.ms/mpt/pricing)
15 | - [Share feedback](https://aka.ms/mpt/feedback)
16 |
17 | ## Get Started
18 | Follow these steps to run your existing Playwright test suite with the service.
19 |
20 | ### Prerequisites
21 |
22 | - An Azure account with an active subscription. If you don't have an Azure subscription, [create a free account](https://aka.ms/mpt/create-azure-subscription) before you begin.
23 | - Your Azure account must be assigned the [Owner](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#owner), [Contributor](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#contributor), or one of the [classic administrator roles](https://learn.microsoft.com/en-us/azure/role-based-access-control/rbac-and-directory-admin-roles#classic-subscription-administrator-roles).
24 | - A Playwright project. If you don't have one, you can clone this repository and navigate to samples/get-started.
25 | - Azure CLI. If you don't have Azure CLI, see [Install Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli)
26 |
27 | ### Create a Workspace
28 |
29 | 1. Sign in to the [Playwright portal](https://aka.ms/mpt/portal) with your Azure account.
30 |
31 | 1. Create the Workspace.
32 |
33 | 
34 |
35 | |Field |Description |
36 | |---------|---------|
37 | |**Workspace Name** | A unique name to identify your workspace.
The name can't contain special characters or whitespace. |
38 | |**Azure Subscription** | Select an Azure subscription where you want to create the workspace. |
39 | |**Region** | This is where test run data will be stored for your workspace. |
40 |
41 | > [!NOTE]
42 | > If you don't see this screen, select an existing workspace and go to the next section.
43 |
44 |
45 | ### Install Microsoft Playwright Testing package
46 |
47 | To use the service, install Microsoft Playwright Testing package.
48 |
49 | ```npm
50 | npm init @azure/microsoft-playwright-testing
51 | ```
52 | This generates `playwright.service.config.ts` file which serves to:
53 |
54 | - Direct and authenticate Playwright to the Microsoft Playwright Testing service.
55 | - Adds a reporter to publish test results and artifacts.
56 |
57 | If you already have this file, the package asks you to override it.
58 |
59 | > [!NOTE]
60 | > Make sure your project uses @playwright/test version 1.47 or above.
61 |
62 |
63 | ### Obtain region endpoint
64 |
65 | 1. In the [Playwright portal](https://aka.ms/mpt/portal), copy the command under **Add region endpoint in your set up**.
66 |
67 | 
68 |
69 | The endpoint URL corresponds to the workspace region. You might see a different endpoint URL in the Playwright portal, depending on the region you selected when creating the workspace.
70 |
71 | > [!NOTE]
72 | > The region end point could be updated. Make sure you copy the latest value from [Playwright portal](https://aka.ms/mpt/portal) .
73 |
74 | ### Set up environment
75 |
76 | Ensure that the `PLAYWRIGHT_SERVICE_URL` that you obtained in previous step is available in your environment.
77 |
78 | We recommend using `dotenv` module to manage your environment. With `dotenv` you'll be using the `.env` file to define your environment variables.
79 |
80 | > [!IMPORTANT]
81 | > Don't forget to add `.env` file to your `.gitignore` file in order to not leak your secrets.
82 |
83 | ```sh
84 | npm i --save-dev dotenv
85 | ```
86 |
87 | `.env` file
88 | ```
89 | PLAYWRIGHT_SERVICE_URL={MY-REGION-ENDPOINT}
90 | ```
91 | Make sure to replace the `{MY-REGION-ENDPOINT}` text placeholder with the value you copied earlier.
92 |
93 | ### Set up Authentication
94 |
95 | To run your Playwright tests in your Microsoft Playwright Testing workspace, you need to authenticate the Playwright client where you are running the tests with the service. This could be your local dev machine or CI machine.
96 |
97 | The service offers two authentication methods: Microsoft Entra ID and Access Tokens.
98 |
99 | Microsoft Entra ID uses your Azure credentials, requiring a sign-in to your Azure account for secure access. Alternatively, you can generate an access token from your Playwright workspace and use it in your setup.
100 |
101 | You can follow any one of the authentication methods below:
102 |
103 | > We strongly recommend using Microsoft Entra ID for authentication to the service.
104 |
105 | #### Set up authtication using Microsoft Entra ID
106 |
107 | Microsoft Entra ID is the default and recommended authentication for the service. From your local dev machine, you can use [Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli) to sign-in
108 |
109 | ```CLI
110 | az login
111 | ```
112 |
113 | **NOTE**: If you are a part of multiple Microsoft Entra tenants, make sure you sign-in to the tenant where your workspace belongs. You can get the tenant id from Azure portal, see [Find your Microsoft Entra Tenant](https://learn.microsoft.com/azure/azure-portal/get-subscription-tenant-id#find-your-microsoft-entra-tenant). Once you get the ID, sign-in using the command `az login --tenant `
114 |
115 | #### Set up authentication using access tokens
116 |
117 | You can generate an access token from your Playwright Testing workspace and use it in your setup. However, we strongly recommend Microsoft Entra ID for authentication due to its enhanced security. Access tokens, while convenient, function like long-lived passwords and are more susceptible to being compromised.
118 |
119 | 1. Authentication using access tokens is disabled by default. To enable, see [Enable access-token based authentication](https://aka.ms/mpt/authentication)
120 |
121 | 2. [Set up authentication using access tokens](https://aka.ms/mpt/access-token)
122 |
123 | > We strongly recommend using Microsoft Entra ID for authentication to the service. If you are using access tokens, see [How to Manage Access Tokens](https://aka.ms/mpt/access-token)
124 |
125 | ### Run the tests
126 |
127 | Run Playwright tests against browsers managed by the service using the configuration you created above.
128 |
129 | ```sh
130 | npx playwright test --config=playwright.service.config.ts --workers=20
131 | ```
132 |
133 | ## Next steps
134 | - Run tests in a [CI/CD pipeline.](https://aka.ms/mpt/configure-pipeline)
135 |
136 | - Learn how to [manage access](https://aka.ms/mpt/manage-access) to the created workspace.
137 |
138 | - Experiment with different number of workers to [determine the optimal configuration of your test suite](https://aka.ms/mpt/parallelism).
139 |
140 |
141 | ## Contributing
142 |
143 | This project welcomes contributions and suggestions. Most contributions require you to agree to a
144 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
145 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
146 |
147 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide
148 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
149 | provided by the bot. You will only need to do this once across all repos using our CLA.
150 |
151 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
152 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
153 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
154 |
155 | ## Trademarks
156 |
157 | This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft
158 | trademarks or logos is subject to and must follow
159 | [Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general).
160 | Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship.
161 | Any use of third-party trademarks or logos is subject to those third-party's policies.
162 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Security
4 |
5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
6 |
7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
8 |
9 | ## Reporting Security Issues
10 |
11 | **Please do not report security vulnerabilities through public GitHub issues.**
12 |
13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
14 |
15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
16 |
17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
18 |
19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
20 |
21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
22 | * Full paths of source file(s) related to the manifestation of the issue
23 | * The location of the affected source code (tag/branch/commit or direct URL)
24 | * Any special configuration required to reproduce the issue
25 | * Step-by-step instructions to reproduce the issue
26 | * Proof-of-concept or exploit code (if possible)
27 | * Impact of the issue, including how an attacker might exploit the issue
28 |
29 | This information will help us triage your report more quickly.
30 |
31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
32 |
33 | ## Preferred Languages
34 |
35 | We prefer all communications to be in English.
36 |
37 | ## Policy
38 |
39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
40 |
41 |
42 |
--------------------------------------------------------------------------------
/SUPPORT.md:
--------------------------------------------------------------------------------
1 |
2 | # Support for Microsoft Playwright Testing
3 |
4 | We're here to help you with any questions, issues, or concerns you may have while using [Your Project Name]. You have two options for getting support:
5 |
6 | ## 1. GitHub Issue Tracker
7 |
8 | If you encounter a bug, have a feature request, or need general assistance, you can create an issue on our GitHub repository [here](https://aka.ms/mpt/feedback)
9 |
10 | Our team will review your issue and provide assistance as soon as possible. Please be patient and responsive to any follow-up questions or requests for clarification.
11 |
12 | ## 2. Azure Customer Support
13 |
14 | You can also raise a support ticket with Azure Customer Support. This option is suitable for critical issues or situations where you prefer not to disclose certain information. To create a support ticket with Azure, follow these steps:
15 |
16 |
17 | 1. Log in to [Playwright Testing Portal](https://aka.ms/mpt/portal).
18 |
19 | 2. Select '?' icon on the top bar.
20 |
21 | 3. Select "Help + Support on Azure portal". This will take you to Azure Portal where you can raise a new support request.
22 |
23 |
24 | Thank you for using Microsoft Playwright Testing, we appreciate your feedback and support!
25 |
--------------------------------------------------------------------------------
/samples/.NET/.gitignore:
--------------------------------------------------------------------------------
1 | # The following command works for downloading when using Git for Windows:
2 | # curl -LOf http://gist.githubusercontent.com/kmorcinek/2710267/raw/.gitignore
3 | #
4 | # Download this file using PowerShell v3 under Windows with the following comand:
5 | # Invoke-WebRequest https://gist.githubusercontent.com/kmorcinek/2710267/raw/ -OutFile .gitignore
6 | #
7 | # or wget:
8 | # wget --no-check-certificate http://gist.githubusercontent.com/kmorcinek/2710267/raw/.gitignore
9 |
10 | # User-specific files
11 | *.suo
12 | *.user
13 | *.sln.docstates
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Rr]elease/
18 | x64/
19 | [Bb]in/
20 | [Oo]bj/
21 | # build folder is nowadays used for build scripts and should not be ignored
22 | #build/
23 |
24 | # NuGet Packages
25 | *.nupkg
26 | # The packages folder can be ignored because of Package Restore
27 | **/packages/*
28 | # except build/, which is used as an MSBuild target.
29 | !**/packages/build/
30 | # Uncomment if necessary however generally it will be regenerated when needed
31 | #!**/packages/repositories.config
32 |
33 | # MSTest test Results
34 | [Tt]est[Rr]esult*/
35 | [Bb]uild[Ll]og.*
36 |
37 | *_i.c
38 | *_p.c
39 | *.ilk
40 | *.meta
41 | *.obj
42 | *.pch
43 | *.pdb
44 | *.pgc
45 | *.pgd
46 | *.rsp
47 | *.sbr
48 | *.tlb
49 | *.tli
50 | *.tlh
51 | *.tmp
52 | *.tmp_proj
53 | *.log
54 | *.vspscc
55 | *.vssscc
56 | .builds
57 | *.pidb
58 | *.scc
59 |
60 | # Visual C++ cache files
61 | ipch/
62 | *.aps
63 | *.ncb
64 | *.opensdf
65 | *.sdf
66 | *.cachefile
67 |
68 | # Visual Studio profiler
69 | *.psess
70 | *.vsp
71 | *.vspx
72 |
73 | # Guidance Automation Toolkit
74 | *.gpState
75 |
76 | # ReSharper is a .NET coding add-in
77 | _ReSharper*/
78 | *.[Rr]e[Ss]harper
79 |
80 | # TeamCity is a build add-in
81 | _TeamCity*
82 |
83 | # DotCover is a Code Coverage Tool
84 | *.dotCover
85 |
86 | # NCrunch
87 | *.ncrunch*
88 | .*crunch*.local.xml
89 |
90 | # Installshield output folder
91 | [Ee]xpress/
92 |
93 | # DocProject is a documentation generator add-in
94 | DocProject/buildhelp/
95 | DocProject/Help/*.HxT
96 | DocProject/Help/*.HxC
97 | DocProject/Help/*.hhc
98 | DocProject/Help/*.hhk
99 | DocProject/Help/*.hhp
100 | DocProject/Help/Html2
101 | DocProject/Help/html
102 |
103 | # Click-Once directory
104 | publish/
105 |
106 | # Publish Web Output
107 | *.Publish.xml
108 |
109 | # Windows Azure Build Output
110 | csx
111 | *.build.csdef
112 |
113 | # Windows Store app package directory
114 | AppPackages/
115 |
116 | # Others
117 | *.Cache
118 | ClientBin/
119 | [Ss]tyle[Cc]op.*
120 | ~$*
121 | *~
122 | *.dbmdl
123 | *.[Pp]ublish.xml
124 | *.pfx
125 | *.publishsettings
126 | modulesbin/
127 | tempbin/
128 |
129 | # EPiServer Site file (VPP)
130 | AppData/
131 |
132 | # RIA/Silverlight projects
133 | Generated_Code/
134 |
135 | # Backup & report files from converting an old project file to a newer
136 | # Visual Studio version. Backup files are not needed, because we have git ;-)
137 | _UpgradeReport_Files/
138 | Backup*/
139 | UpgradeLog*.XML
140 | UpgradeLog*.htm
141 |
142 | # vim
143 | *.txt~
144 | *.swp
145 | *.swo
146 |
147 | # Temp files when opening LibreOffice on ubuntu
148 | .~lock.*
149 |
150 | # svn
151 | .svn
152 |
153 | # CVS - Source Control
154 | **/CVS/
155 |
156 | # Remainings from resolving conflicts in Source Control
157 | *.orig
158 |
159 | # SQL Server files
160 | **/App_Data/*.mdf
161 | **/App_Data/*.ldf
162 | **/App_Data/*.sdf
163 |
164 |
165 | #LightSwitch generated files
166 | GeneratedArtifacts/
167 | _Pvt_Extensions/
168 | ModelManifest.xml
169 |
170 | # =========================
171 | # Windows detritus
172 | # =========================
173 |
174 | # Windows image file caches
175 | Thumbs.db
176 | ehthumbs.db
177 |
178 | # Folder config file
179 | Desktop.ini
180 |
181 | # Recycle Bin used on file shares
182 | $RECYCLE.BIN/
183 |
184 | # OS generated files #
185 | Icon?
186 |
187 | # Mac desktop service store files
188 | .DS_Store
189 |
190 | # SASS Compiler cache
191 | .sass-cache
192 |
193 | # Visual Studio 2014 CTP
194 | **/*.sln.ide
195 |
196 | # Visual Studio temp something
197 | .vs/
198 |
199 | # dotnet stuff
200 | project.lock.json
201 |
202 | # VS 2015+
203 | *.vc.vc.opendb
204 | *.vc.db
205 |
206 | # Rider
207 | .idea/
208 |
209 | # Visual Studio Code
210 | .vscode/
211 |
212 | # Output folder used by Webpack or other FE stuff
213 | **/node_modules/*
214 | # **/wwwroot/*
215 |
216 | # SpecFlow specific
217 | *.feature.cs
218 | *.feature.xlsx.*
219 | *.Specs_*.html
220 |
221 | # UWP Projects
222 | AppPackages/
223 |
--------------------------------------------------------------------------------
/samples/.NET/MSTest/.runsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | 20
7 | ClassLevel
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | chromium
20 | 5000
21 |
22 | true
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/samples/.NET/MSTest/PlaywrightTestsMSTest.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 | enable
7 |
8 | false
9 | true
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/samples/.NET/MSTest/README.md:
--------------------------------------------------------------------------------
1 | # Scale Playwright .NET tests with Microsoft Playwright Testing (Experimental)
2 |
3 | This sample demonstrates how to run Playwright .NET tests at scale using Microsoft Playwright Testing. It showcases the benefits of accelerating test suite completion by leveraging more parallel cloud browsers. The tests are executed using MSTest test runner.
4 |
5 | Note: Since service integration is done via [playwright MSTEST base class](https://playwright.dev/dotnet/docs/test-runners) which uses BrowserService so it only works out of the box when you use one of the following base class BrowserTest, Page, ContextTest
6 |
7 | If you have not yet created a workspace, please follow the [Get Started guide](../../../README.md#get-started)
8 |
9 | ## Sample setup
10 | 1. Clone this sample:
11 | ```powershell
12 | git clone https://github.com/microsoft/playwright-testing-service
13 | cd playwright-testing-service/samples/.NET/MSTest
14 | ```
15 |
16 | 1. Install dependencies:
17 | ```powershell
18 | dotnet add package Microsoft.Playwright.MSTest
19 | ```
20 | 1. Build the project so the playwright.ps1 is available inside the bin directory:
21 | ```powershell
22 | dotnet build
23 | ```
24 |
25 |
26 | 1. Install required browsers by replacing netX with the actual output folder name, e.g. net6.0:
27 |
28 | ```powershell
29 | pwsh bin/Debug/netX/playwright.ps1 install
30 | ```
31 |
32 | If pwsh is not available, you have to [install PowerShell](https://docs.microsoft.com/powershell/scripting/install/installing-powershell).
33 |
34 | 1. Set up Authentication using Access Tokens
35 | Currently, only access tokens are supported for NUnit. See [Set up authentication using access tokens](../../../README.md#set-up-authentication-using-access-tokens)
36 |
37 | 1. Set access token generated above as environment variable for your project:
38 | ```powershell
39 | $env:PLAYWRIGHT_SERVICE_ACCESS_TOKEN= # Paste Access Token value from previous step
40 | ```
41 | NOTE: If you are using Playwright version 1.39, the name of this variable should be `PLAYWRIGHT_SERVICE_ACCESS_KEY`.
42 |
43 | 1. In the [Playwright portal](https://aka.ms/mpt/portal), copy the command under **Add region endpoint in your set up** and set the following environment variable:
44 | ```powershell
45 | $env:PLAYWRIGHT_SERVICE_URL= # Paste region endpoint URL
46 | ```
47 |
48 |
49 | ## Run tests
50 |
51 | Run Playwright tests against browsers managed by the service using the configuration you created above. You can run up to 50 parallel workers with the service
52 | ```powershell
53 | dotnet test --settings:.runsettings -- MSTest.Parallelize.Workers=10
54 | ```
55 | Note that by default MSTest will run all classes in parallel, while running tests inside each class sequentially (ExecutionScope.ClassLevel). You can adjust this behavior by using the following CLI parameter or using a .runsettings file as shown above. Running tests in parallel at the method level (ExecutionScope.MethodLevel) is not supported. Please refer to [Playwright documentation](https://playwright.dev/dotnet/docs/test-runners#running-mstest-tests-in-parallel).
56 |
57 | ## Add more configuration
58 |
59 | You can use the following environment variables to specify configuration parameters for the service:
60 |
61 |
62 | 1. **PLAYWRIGHT_SERVICE_EXPOSE_NETWORK**: This variable allows you to control the network access for your service. You can set it to `` to enable the service to access the localhost and test locally hosted applications.
63 |
64 | Example:
65 | ```powershell
66 | $env:PLAYWRIGHT_SERVICE_EXPOSE_NETWORK = ""
67 | ```
68 |
69 | 2. **PLAYWRIGHT_SERVICE_OS**: Use this variable to specify the operating system where browsers are hosted. You can choose between 'linux' or 'windows' based on your requirements.
70 |
71 | Example:
72 | ```powershell
73 | $env:PLAYWRIGHT_SERVICE_OS = "linux"
74 | ```
75 |
76 | 3. **PLAYWRIGHT_SERVICE_RUN_ID**: This variable allows you to change the ID of the test run. The run ID is a unique identifier for a test run and is used to track test runs in the portal.
77 |
78 | Example :
79 | ```powershell
80 | $env:PLAYWRIGHT_SERVICE_RUN_ID = "my_custom_runId"
81 | ```
82 |
--------------------------------------------------------------------------------
/samples/.NET/MSTest/Tests.cs:
--------------------------------------------------------------------------------
1 | using System.Text.RegularExpressions;
2 | using System.Threading.Tasks;
3 | using Microsoft.Playwright;
4 | using Microsoft.Playwright.MSTest;
5 | using Microsoft.VisualStudio.TestTools.UnitTesting;
6 |
7 | namespace PlaywrightTests;
8 |
9 | [TestClass]
10 | public class Tests : PageTest
11 |
12 | {
13 | [TestMethod]
14 |
15 | public async Task HomepageHasPlaywrightInTitleAndGetStartedLinkLinkingtoTheIntroPage()
16 | {
17 |
18 | await Page.GotoAsync("https://playwright.dev");
19 |
20 | // Expect a title "to contain" a substring.
21 | await Expect(Page).ToHaveTitleAsync(new Regex("Playwright"));
22 |
23 | // create a locator
24 | var getStarted = Page.GetByRole(AriaRole.Link, new() { Name = "Get started" });
25 |
26 | // Expect an attribute "to be strictly equal" to the value.
27 | await Expect(getStarted).ToHaveAttributeAsync("href", "/docs/intro");
28 |
29 | // Click the get started link.
30 | await getStarted.ClickAsync();
31 |
32 | // Expects the URL to contain intro.
33 | await Expect(Page).ToHaveURLAsync(new Regex(".*intro"));
34 |
35 | }
36 | }
--------------------------------------------------------------------------------
/samples/.NET/NUnit/.github/workflows/dotnet.yml:
--------------------------------------------------------------------------------
1 | # This workflow will build a .NET project
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
3 |
4 | name: Nunit Playwright Test Sample
5 | # on: [push]
6 |
7 | permissions: # Required when using AuthType as EntraId
8 | id-token: write
9 | contents: read
10 | jobs:
11 | build:
12 | runs-on: ubuntu-latest
13 | env:
14 | working-directory: './samples/.NET/NUnit'
15 | environment: Production
16 | steps:
17 | - uses: actions/checkout@v4
18 | - name: Setup .NET
19 | uses: actions/setup-dotnet@v4
20 | with:
21 | dotnet-version: 8.0.x
22 | - name: Restore dependencies
23 | run: dotnet restore
24 | working-directory: ${{env.working-directory}}
25 | - name: Build
26 | run: dotnet build --no-restore
27 | working-directory: ${{env.working-directory}}
28 | - name: Azure CLI Login # Required when using AuthType as EntraId
29 | uses: azure/login@v2
30 | with:
31 | client-id: ${{ secrets.AZURE_CLIENT_ID }} # Create ManagedIdentity in azure and assign required roles
32 | tenant-id: ${{ secrets.AZURE_TENANT_ID }}
33 | subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
34 | - name: Test
35 | run: dotnet test --no-build --verbosity normal --settings .runsettings
36 | working-directory: ${{env.working-directory}}
37 | env:
38 | PLAYWRIGHT_SERVICE_URL: ${{ secrets.PLAYWRIGHT_SERVICE_URL }}
39 | #PLAYWRIGHT_SERVICE_ACCESS_TOKEN: ${{ secrets.PLAYWRIGHT_SERVICE_ACCESS_TOKEN }} for AccessToken Auth
40 |
--------------------------------------------------------------------------------
/samples/.NET/NUnit/.runsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | 10
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | chromium
29 | 5000
30 |
31 | false
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/samples/.NET/NUnit/BrowserTestWithArtifact.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Playwright;
2 | using Microsoft.Playwright.NUnit;
3 | using NUnit.Framework;
4 | using NUnit.Framework.Interfaces;
5 |
6 | namespace PlaywrightTests
7 | {
8 | /*
9 | * BrowserTestWithArtifact is a base class for tests that require Playwright page and context.
10 | * It provides a setup and teardown methods for the test to run in a browser context.
11 | * It also provides a way to enable trace, screenshot, and video artifacts for the test.
12 | * Users need to inherit this class instead of BrowserTest to write tests.
13 | */
14 | [TestFixture]
15 | public class BrowserTestWithArtifact : BrowserTest
16 | {
17 |
18 | // Declare the Context and Page
19 | public IPage Page { get; private set; } = null!;
20 | public IBrowserContext Context { get; private set; } = null!;
21 | public virtual BrowserNewContextOptions ContextOptions()
22 | {
23 | return new()
24 | {
25 | Locale = "en-US",
26 | ColorScheme = ColorScheme.Light,
27 | RecordVideoDir = ".videos"
28 | };
29 | }
30 |
31 | [SetUp]
32 | public async Task Setup()
33 | {
34 | // Create Context
35 | Context = await Browser.NewContextAsync(ContextOptions());
36 |
37 | // Enable Trace
38 | await Context.Tracing.StartAsync(new()
39 | {
40 | Title = $"{TestContext.CurrentContext.Test.Name}",
41 | Screenshots = true,
42 | Snapshots = true,
43 | Sources = true
44 | });
45 | // Create a new page
46 | Page = await Context.NewPageAsync();
47 | }
48 |
49 | [TearDown]
50 | public async Task TearDown()
51 | {
52 | /* On Windows, Its possble that path exceed 255 characters.
53 | * if it does, feel free to change the path to a shorter one.
54 | * possibly removing test name.
55 | */
56 | // Stop trace and add it as an attachment
57 | var tracePath = Path.Combine(
58 | TestContext.CurrentContext.WorkDirectory,
59 | "playwright-traces",
60 | $"{TestContext.CurrentContext.Test.Name}.{Guid.NewGuid()}.zip"
61 | );
62 | await Context.Tracing.StopAsync(new()
63 | {
64 | Path = tracePath
65 | });
66 | TestContext.AddTestAttachment(tracePath, description: "Trace");
67 |
68 | // Take a screenshot on error and add it as an attachment
69 | if (TestContext.CurrentContext.Result.Outcome == ResultState.Error)
70 | {
71 | var screenshotPath = Path.Combine(
72 | TestContext.CurrentContext.WorkDirectory,
73 | "playwright-screenshot",
74 | $"{TestContext.CurrentContext.Test.Name}.{Guid.NewGuid()}.png");
75 | await Page.ScreenshotAsync(new()
76 | {
77 | Path = screenshotPath,
78 | });
79 | TestContext.AddTestAttachment(screenshotPath, description: "Screenshot");
80 | }
81 |
82 | // Enable video artifact and add it as an attachment, Context close is required to save the video
83 | await Context.CloseAsync();
84 | var videoPath = Path.Combine(
85 | TestContext.CurrentContext.WorkDirectory,
86 | "playwright-videos",
87 | $"{TestContext.CurrentContext.Test.Name}.{Guid.NewGuid()}.webm");
88 | if (Page.Video != null)
89 | {
90 | await Page.Video.SaveAsAsync(videoPath);
91 | TestContext.AddTestAttachment(videoPath, description: "Video");
92 | }
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/samples/.NET/NUnit/ContextTestWithArtifact.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Playwright;
2 | using Microsoft.Playwright.NUnit;
3 | using NUnit.Framework;
4 | using NUnit.Framework.Interfaces;
5 |
6 | namespace PlaywrightTests
7 | {
8 | /*
9 | * ContextTestWithArtifact is a base class for tests that require Playwright context and page.
10 | * It provides a setup and teardown methods for the test to run in a browser context.
11 | * It also provides a way to enable trace, screenshot, and video artifacts for the test.
12 | * Users need to inherit this class instead of ContextTest to write tests.
13 | */
14 | [TestFixture]
15 | public class ContextTestWithArtifact : ContextTest
16 | {
17 |
18 | // Declare Page
19 | public IPage Page { get; private set; } = null!;
20 |
21 | [SetUp]
22 | public async Task Setup()
23 | {
24 | TestContext.WriteLine("Browser: " + BrowserName);
25 | // Enable Trace
26 | await Context.Tracing.StartAsync(new()
27 | {
28 | Title = $"{TestContext.CurrentContext.Test.Name}",
29 | Screenshots = true,
30 | Snapshots = true,
31 | Sources = true
32 | });
33 | Page = await Context.NewPageAsync();
34 | }
35 |
36 | [TearDown]
37 | public async Task TearDown()
38 | {
39 | /* On Windows, Its possble that path exceed 255 characters.
40 | * if it does, feel free to change the path to a shorter one.
41 | * possibly removing test name.
42 | */
43 | // Stop trace and add it as an attachment
44 | var tracePath = Path.Combine(
45 | TestContext.CurrentContext.WorkDirectory,
46 | "playwright-traces",
47 | $"{TestContext.CurrentContext.Test.Name}.{Guid.NewGuid()}.zip"
48 | );
49 | await Context.Tracing.StopAsync(new()
50 | {
51 | Path = tracePath
52 | });
53 | TestContext.AddTestAttachment(tracePath, description: "Trace");
54 | // Take a screenshot on error and add it as an attachment
55 | if (TestContext.CurrentContext.Result.Outcome == ResultState.Error)
56 | {
57 | var screenshotPath = Path.Combine(
58 | TestContext.CurrentContext.WorkDirectory,
59 | "playwright-screenshot",
60 | $"{TestContext.CurrentContext.Test.Name}.{Guid.NewGuid()}.png");
61 | await Page.ScreenshotAsync(new()
62 | {
63 | Path = screenshotPath,
64 | });
65 | TestContext.AddTestAttachment(screenshotPath, description: "Screenshot");
66 | }
67 |
68 | // Enable video artifact and add it as an attachment, Context close is required to save the video
69 | await Context.CloseAsync();
70 | var videoPath = Path.Combine(
71 | TestContext.CurrentContext.WorkDirectory,
72 | "playwright-videos",
73 | $"{TestContext.CurrentContext.Test.Name}.{Guid.NewGuid()}.webm");
74 | if (Page.Video != null)
75 | {
76 | await Page.Video.SaveAsAsync(videoPath);
77 | TestContext.AddTestAttachment(videoPath, description: "Video");
78 | }
79 | }
80 |
81 | public override BrowserNewContextOptions ContextOptions()
82 | {
83 | // Video enable via context option overriding the default context option.
84 | var options = base.ContextOptions();
85 | options.RecordVideoDir = ".videos"; // temp path to enable video recording
86 | return options;
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/samples/.NET/NUnit/PageTestWithArtifact.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Playwright;
2 | using Microsoft.Playwright.NUnit;
3 | using NUnit.Framework;
4 | using NUnit.Framework.Interfaces;
5 |
6 | namespace PlaywrightTests
7 | {
8 | /*
9 | * PageTestWithArtifact is a base class for tests that require Playwright page and context.
10 | * It provides a setup and teardown methods for the test to run in a browser context.
11 | * It also provides a way to enable trace, screenshot, and video artifacts for the test.
12 | * Users need to inherit this class instead of PageTest to write tests.
13 | */
14 | [TestFixture]
15 | public class PageTestWithArtifact : PageTest
16 | {
17 |
18 | [SetUp]
19 | public async Task Setup()
20 | {
21 | TestContext.WriteLine("Browser: " + BrowserName);
22 | // Enable Trace
23 | await Context.Tracing.StartAsync(new()
24 | {
25 | Title = $"{TestContext.CurrentContext.Test.Name}",
26 | Screenshots = true,
27 | Snapshots = true,
28 | Sources = true
29 | });
30 | }
31 |
32 | [TearDown]
33 | public async Task TearDown()
34 | {
35 | /* On Windows, Its possble that path exceed 255 characters.
36 | * if it does, feel free to change the path to a shorter one.
37 | * possibly removing test name.
38 | */
39 | // Stop trace and add it as an attachment
40 | var tracePath = Path.Combine(
41 | TestContext.CurrentContext.WorkDirectory,
42 | "playwright-traces",
43 | $"{TestContext.CurrentContext.Test.Name}.{Guid.NewGuid()}.zip"
44 | );
45 | await Context.Tracing.StopAsync(new()
46 | {
47 | Path = tracePath
48 | });
49 | TestContext.AddTestAttachment(tracePath, description: "Trace");
50 |
51 | // Take a screenshot on error and add it as an attachment
52 | if (TestContext.CurrentContext.Result.Outcome == ResultState.Error)
53 | {
54 | var screenshotPath = Path.Combine(
55 | TestContext.CurrentContext.WorkDirectory,
56 | "playwright-screenshot",
57 | $"{TestContext.CurrentContext.Test.Name}.{Guid.NewGuid()}.png");
58 | await Page.ScreenshotAsync(new()
59 | {
60 | Path = screenshotPath,
61 | });
62 | TestContext.AddTestAttachment(screenshotPath, description: "Screenshot");
63 | }
64 |
65 | // Enable video artifact and add it as an attachment, Context close is required to save the video
66 | await Context.CloseAsync();
67 | var videoPath = Path.Combine(
68 | TestContext.CurrentContext.WorkDirectory,
69 | "playwright-videos",
70 | $"{TestContext.CurrentContext.Test.Name}.{Guid.NewGuid()}.webm");
71 | if (Page.Video != null)
72 | {
73 | await Page.Video.SaveAsAsync(videoPath);
74 | TestContext.AddTestAttachment(videoPath, description: "Video");
75 | }
76 | }
77 |
78 | public override BrowserNewContextOptions ContextOptions()
79 | {
80 | // Video enable via context option overriding the default context option.
81 | var options = base.ContextOptions();
82 | options.RecordVideoDir = ".videos"; // temp path to enable video recording
83 | return options;
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/samples/.NET/NUnit/PlaywrightServiceSetup.cs:
--------------------------------------------------------------------------------
1 | using Azure.Developer.MicrosoftPlaywrightTesting.NUnit;
2 | using NUnit.Framework;
3 |
4 | namespace PlaywrightTests; // Remember to change this as per your project namespace
5 |
6 | [SetUpFixture]
7 | public class PlaywrightServiceSetup : PlaywrightServiceNUnit { };
--------------------------------------------------------------------------------
/samples/.NET/NUnit/PlaywrightTestWithArtifact.cs:
--------------------------------------------------------------------------------
1 | using Azure.Developer.MicrosoftPlaywrightTesting.TestLogger;
2 | using Microsoft.Playwright;
3 | using Microsoft.Playwright.NUnit;
4 | using Microsoft.Playwright.TestAdapter;
5 | using NUnit.Framework;
6 | using NUnit.Framework.Interfaces;
7 | using System.Text.Json.Serialization;
8 | using System.Text.Json;
9 |
10 | namespace PlaywrightTests
11 | {
12 | /*
13 | * PlaywrightTestWithArtifact is a base class for tests that require Playwright context and page.
14 | * It provides a setup and teardown methods for the test to run in a browser context.
15 | * It also provides a way to enable trace, screenshot, and video artifacts for the test.
16 | * Users need to inherit this class instead of PlaywrightTest to write tests.
17 | */
18 | [TestFixture]
19 | public class PlaywrightTestWithArtifact : PlaywrightTest
20 | {
21 | // Declare Browser, Context and Page
22 | public IPage Page { get; private set; } = null!;
23 | public IBrowserContext Context { get; private set; } = null!;
24 | public IBrowser Browser { get; private set; } = null!;
25 |
26 | public virtual BrowserNewContextOptions ContextOptions()
27 | {
28 | return new()
29 | {
30 | Locale = "en-US",
31 | ColorScheme = ColorScheme.Light,
32 | RecordVideoDir = ".videos"
33 | };
34 | }
35 |
36 | [SetUp]
37 | public async Task Setup()
38 | {
39 | if (TestContext.Parameters.Get(RunSettingKey.UseCloudHostedBrowsers) == "false")
40 | {
41 | Browser = await BrowserType.LaunchAsync(PlaywrightSettingsProvider.LaunchOptions);
42 | } else {
43 | /* Connect Remote Browser using BrowserType.ConnectAsync
44 | * fetches service connect options like wsEndpoint and options
45 | * add x-playwright-launch-options header to pass launch options likes channel, headless, etc.
46 | */
47 | var playwrightService = new PlaywrightService();
48 | var connectOptions = await playwrightService.GetConnectOptionsAsync();
49 | var launchOptionString = System.Text.Json.JsonSerializer.Serialize(PlaywrightSettingsProvider.LaunchOptions, new JsonSerializerOptions() { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull });
50 | if (connectOptions.Options!.Headers != null)
51 | {
52 | connectOptions.Options.Headers = connectOptions.Options.Headers.Concat(new Dictionary { { "x-playwright-launch-options", launchOptionString } });
53 | }
54 | else
55 | {
56 | connectOptions.Options.Headers = new Dictionary { { "x-playwright-launch-options", launchOptionString } };
57 | }
58 | Browser = await BrowserType.ConnectAsync(connectOptions.WsEndpoint!, connectOptions.Options!);
59 | }
60 |
61 | // Create context and page
62 | Context = await Browser.NewContextAsync(ContextOptions());
63 |
64 | // Enable Trace
65 | await Context.Tracing.StartAsync(new()
66 | {
67 | Title = $"{TestContext.CurrentContext.Test.Name}",
68 | Screenshots = true,
69 | Snapshots = true,
70 | Sources = true
71 | });
72 | // Create a new page
73 | Page = await Context.NewPageAsync();
74 | }
75 |
76 | [TearDown]
77 | public async Task TearDown()
78 | {
79 | /* On Windows, Its possble that path exceed 255 characters.
80 | * if it does, feel free to change the path to a shorter one.
81 | * possibly removing test name.
82 | */
83 | // Stop trace and add it as an attachment
84 | var tracePath = Path.Combine(
85 | TestContext.CurrentContext.WorkDirectory,
86 | "playwright-traces",
87 | $"{TestContext.CurrentContext.Test.Name}.{Guid.NewGuid()}.zip"
88 | );
89 | await Context.Tracing.StopAsync(new()
90 | {
91 | Path = tracePath
92 | });
93 | TestContext.AddTestAttachment(tracePath, description: "Trace");
94 |
95 | // Take a screenshot on error and add it as an attachment
96 | if (TestContext.CurrentContext.Result.Outcome == ResultState.Error)
97 | {
98 | var screenshotPath = Path.Combine(
99 | TestContext.CurrentContext.WorkDirectory,
100 | "playwright-screenshot",
101 | $"{TestContext.CurrentContext.Test.Name}.{Guid.NewGuid()}.png");
102 | await Page.ScreenshotAsync(new()
103 | {
104 | Path = screenshotPath,
105 | });
106 | TestContext.AddTestAttachment(screenshotPath, description: "Screenshot");
107 | }
108 |
109 | // Enable video artifact and add it as an attachment, Context close is required to save the video
110 | await Context.CloseAsync();
111 | var videoPath = Path.Combine(
112 | TestContext.CurrentContext.WorkDirectory,
113 | "playwright-videos",
114 | $"{TestContext.CurrentContext.Test.Name}.{Guid.NewGuid()}.webm");
115 | if (Page.Video != null)
116 | {
117 | await Page.Video.SaveAsAsync(videoPath);
118 | TestContext.AddTestAttachment(videoPath, description: "Video");
119 | }
120 | await Browser.CloseAsync();
121 | }
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/samples/.NET/NUnit/PlaywrightTestsNUnit.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 | enable
7 |
8 | false
9 | true
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/samples/.NET/NUnit/README.md:
--------------------------------------------------------------------------------
1 | # Run Playwright .NET tests with Microsoft Playwright Testing
2 |
3 | This sample demonstrates how to run Playwright .NET tests at scale using Microsoft Playwright Testing. It showcases the benefits of accelerating test suite completion by leveraging more parallel cloud browsers. The tests are executed using NUnit test runner.
4 |
5 | Note: Since service integration is done via [playwright NUnit base class](https://playwright.dev/dotnet/docs/test-runners) which uses BrowserService so it only works out of the box when you use one of the following base class BrowserTest, Page, ContextTest
6 |
7 | If you have not yet created a workspace, please follow the [Get Started guide](../../../README.md#get-started)
8 |
9 | ### Sample setup
10 | 1. Clone this sample:
11 | ```powershell
12 | git clone https://github.com/microsoft/playwright-testing-service
13 | cd playwright-testing-service/samples/.NET/NUnit
14 | ```
15 |
16 | 1. Install dependencies:
17 | ```powershell
18 | dotnet add package Microsoft.Playwright.NUnit
19 | ```
20 | 1. Install service package
21 | ```powershell
22 | dotnet add package Azure.Developer.MicrosoftPlaywrightTesting.NUnit --prerelease
23 | ```
24 |
25 | 1. Build the project so the playwright.ps1 is available inside the bin directory:
26 | ```powershell
27 | dotnet build
28 | ```
29 |
30 | 1. Install required browsers by replacing netX with the actual output folder name, e.g. net6.0:
31 |
32 | ```powershell
33 | pwsh bin/Debug/netX/playwright.ps1 install
34 | ```
35 |
36 | If pwsh is not available, you have to [install PowerShell](https://docs.microsoft.com/powershell/scripting/install/installing-powershell).
37 |
38 | 1. Set up Authentication
39 |
40 | To run your Playwright tests in your Microsoft Playwright Testing workspace, you need to authenticate the Playwright client where you are running the tests with the service. This could be your local dev machine or CI machine. To run tests from your local machine, you can use Azure CLI. Run this command to sign-in
41 |
42 | ```CLI
43 | az login
44 | ```
45 | **NOTE**: If you are a part of multiple Microsoft Entra tenants, make sure you sign-in to the tenant where your workspace belongs. You can get the tenant id from Azure portal, see [Find your Microsoft Entra Tenant](https://learn.microsoft.com/en-us/azure/azure-portal/get-subscription-tenant-id#find-your-microsoft-entra-tenant). Once you get the id, sign in using the command `az login --tenant `
46 |
47 | 1. Set up environment:
48 | In the [Playwright portal](https://aka.ms/mpt/portal), copy the command under **Add region endpoint in your set up** and set the following environment variable:
49 |
50 | ```bash
51 | PLAYWRIGHT_SERVICE_URL= # Paste region endpoint URL
52 | ```
53 |
54 | ### Run tests
55 |
56 | Run Playwright tests against browsers managed by the service using the configuration you created above. You can run up to 50 parallel workers with the service
57 | ```powershell
58 | dotnet test --logger "microsoft-playwright-testing" -- NUnit.NumberOfTestWorkers=20
59 | ```
60 | Note that by default NUnit will run all test files in parallel, while running tests inside each file sequentially (ParallelScope.Self). You can adjust this behavior using the NUnit.NumberOfTestWorkers parameter. Running test in parallel using ParallelScope.All or ParallelScope.Fixtures is not supported. Please refer to [Playwright documentation](https://playwright.dev/dotnet/docs/test-runners#running-nunit-tests-in-parallel).
61 |
62 |
63 | ## Next steps
64 | 1. Follow the [quickstart guide](https://learn.microsoft.com/en-us/azure/playwright-testing/quickstart-run-end-to-end-tests?tabs=playwrightcli&pivots=nunit-test-runner)
65 | 2. [Integrate CI/CD pipelines](https://learn.microsoft.com/en-us/azure/playwright-testing/quickstart-automate-end-to-end-testing?tabs=github&pivots=nunit-test-runner)
66 | 3. Learn about [package options](https://learn.microsoft.com/en-us/azure/playwright-testing/how-to-use-service-config-file?pivots=nunit-test-runner).
67 |
68 | ### Details of the files on this sample project
69 | - [PlaywrightServiceSetup.cs](./PlaywrightServiceSetup.cs): **Requiried** to be added to your project to setup the service, make sure to change the namespace to your project namespace
70 | - [.runsettings](./.runsettings): Optional but recommended to be added to your project to better control service configuration params like Os, RunId, ServiceAuthType, UseCloudHostedBrowsers, ExposeNetwork
71 | - [PageTestWithArtifact.cs](./PageTestWithArtifact.cs): Optional but recommended, If you use PageTest fixture in your test class, this inherit class enable and attach artifacts to the test results
72 | - [ContextTestWithArtifact.cs](./ContextTestWithArtifact.cs): Optional but recommended, If you use ContextTest fixture in your test class, this inherit class enable and attach artifacts to the test results
73 | - [BrowserTestWithArtifact.cs](./BrowserTestWithArtifact.cs): Optional but recommended, If you use BrowserTest fixture in your test class, this inherit class enable and attach artifacts to the test results
74 | - [PlaywrightTestWithArtifact.cs](./PlaywrightTestWithArtifact.cs): Optional but recommended, If you use PlaywrightTest fixture in your test class, this inherit class enable and attach artifacts to the test results
75 |
76 | ### How to extend new fixtures
77 | - public class Tests : PageTestWithArtifact // for PageTest fixture
78 | - public class Tests : ContextTestWithArtifact // for ContextTest fixture
79 | - public class Tests : BrowserTestWithArtifact // for BrowserTest fixture
80 | - public class Tests : PlaywrightTestWithArtifact // for PlaywrightTest fixture
81 |
82 |
--------------------------------------------------------------------------------
/samples/.NET/NUnit/Tests.cs:
--------------------------------------------------------------------------------
1 | using System.Text.RegularExpressions;
2 | using System.Threading.Tasks;
3 | using Microsoft.Playwright;
4 | using Microsoft.Playwright.NUnit;
5 | using NUnit.Framework;
6 |
7 | namespace PlaywrightTests;
8 |
9 | [Parallelizable(ParallelScope.Self)]
10 | [TestFixture]
11 | public class Tests : PageTestWithArtifact
12 | {
13 | [Test]
14 | public async Task HomepageHasPlaywrightInTitleAndGetStartedLinkLinkingtoTheIntroPage()
15 | {
16 | await Page.GotoAsync("https://playwright.dev");
17 |
18 | // Expect a title "to contain" a substring.
19 | await Expect(Page).ToHaveTitleAsync(new Regex("Playwright"));
20 |
21 | // create a locator
22 | var getStarted = Page.GetByRole(AriaRole.Link, new() { Name = "Get started" });
23 |
24 | // Expect an attribute "to be strictly equal" to the value.
25 | await Expect(getStarted).ToHaveAttributeAsync("href", "/docs/intro");
26 |
27 | // Click the get started link.
28 | await getStarted.ClickAsync();
29 |
30 | // Expects the URL to contain intro.
31 | await Expect(Page).ToHaveURLAsync(new Regex(".*intro"));
32 |
33 | }
34 |
35 | [Test]
36 | public async Task RandomlyCaptureScreenshot()
37 | {
38 | await Page.GotoAsync("https://playwright.dev");
39 |
40 | if (TestContext.CurrentContext.Random.Next(1, 100) % 3 == 0)
41 | {
42 | throw new Exception("This will happen randomly");
43 | }
44 | }
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/samples/get-started/.github/workflows/get-started.yml:
--------------------------------------------------------------------------------
1 | # TODO: Place this file in the .github/workflows folder of your repository
2 | # This sample assumes the working directory is ./samples/get-started
3 | name: Get Started sample
4 | on:
5 | push:
6 | branches: [ main, master ]
7 | pull_request:
8 | branches: [ main, master ]
9 | workflow_dispatch:
10 | permissions:
11 | id-token: write
12 | contents: read
13 | jobs:
14 | test:
15 | timeout-minutes: 60
16 | runs-on: ubuntu-latest
17 | steps:
18 | - uses: actions/checkout@v3
19 | - uses: actions/setup-node@v3
20 | with:
21 | node-version: 18
22 | # This step is to sign-in to Azure to run tests from GitHub Action workflow, see: https://learn.microsoft.com/azure/developer/github/connect-from-azure
23 | - name: OIDC Login to Azure Public Cloud with AzPowershell (enableAzPSSession true)
24 | uses: azure/login@v2
25 | with:
26 | client-id: ${{ secrets.AZURE_CLIENT_ID }}
27 | tenant-id: ${{ secrets.AZURE_TENANT_ID }}
28 | subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
29 | enable-AzPSSession: true
30 |
31 | - name: Install dependencies
32 | working-directory: samples/get-started
33 | run: npm install
34 |
35 | - name: Install MPT package
36 | working-directory: samples/get-started
37 | run: npm install @azure/microsoft-playwright-testing
38 |
39 | - name: Run Playwright tests
40 | working-directory: samples/get-started
41 | env:
42 | PLAYWRIGHT_SERVICE_URL: ${{ secrets.PLAYWRIGHT_SERVICE_URL }}
43 | PLAYWRIGHT_SERVICE_RUN_ID: ${{ github.run_id }}-${{ github.run_attempt }}-${{ github.sha }}
44 | run: npx playwright test -c playwright.service.config.ts --workers=30
45 | - uses: actions/upload-artifact@v3
46 | if: always()
47 | with:
48 | name: playwright-report
49 | path: samples/get-started/playwright-report/
50 | retention-days: 10
51 |
--------------------------------------------------------------------------------
/samples/get-started/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | /test-results/
3 | /playwright-report/
4 | /playwright/.cache/
5 | .env
6 | .npmrc
--------------------------------------------------------------------------------
/samples/get-started/README.md:
--------------------------------------------------------------------------------
1 | # Get Started Sample
2 |
3 | This sample uses a basic test to show how the service can speed up test suite completion with more parallel cloud browsers and publish test results and artifacts for easier troubleshooting.
4 |
5 |
6 | If you have not yet created a workspace, please follow the [Get Started guide](../../README.md#get-started)
7 |
8 |
9 | ## Sample setup
10 | 1. Clone this sample:
11 | ```bash
12 | git clone https://github.com/microsoft/playwright-testing-service
13 | cd playwright-testing-service/samples/get-started
14 | ```
15 |
16 | 1. Install dependencies:
17 | ```bash
18 | npm install
19 | ```
20 |
21 | 1. Set up Authentication
22 |
23 | To run your Playwright tests in your Microsoft Playwright Testing workspace, you need to authenticate the Playwright client where you are running the tests with the service. This could be your local dev machine or CI machine. To run tests from your local machine, you can use Azure CLI. Run this command to sign-in
24 |
25 | ```CLI
26 | az login
27 | ```
28 | **NOTE**: If you are a part of multiple Microsoft Entra tenants, make sure you sign-in to the tenant where your workspace belongs. You can get the tenant id from Azure portal, see [Find your Microsoft Entra Tenant](https://learn.microsoft.com/en-us/azure/azure-portal/get-subscription-tenant-id#find-your-microsoft-entra-tenant). Once you get the id, sign in using the command `az login --tenant `
29 |
30 | 1. Create a `.env` file in the sample's directory and define the following environment variable:
31 | In the [Playwright portal](https://aka.ms/mpt/portal), copy the command under **Add region endpoint in your set up** and set the following environment variable:
32 | ```bash
33 | PLAYWRIGHT_SERVICE_URL= # Paste region endpoint URL
34 | ```
35 |
36 | ## Run tests
37 |
38 | Run Playwright tests against browsers managed by the service using the configuration you created above. You can run up to 50 parallel workers with the service
39 |
40 | ```bash
41 | npx playwright test --config=playwright.service.config.ts --workers=20
42 | ```
43 |
44 | ## Run tests in a GitHub workflow
45 | 1. Copy the file [get-started.yaml](.github/workflows/get-started.yml) to your repository's `.github/workflows` directory.
46 | 1. Then follow the instructions in the article [Configure Playwright Service in a CI/CD pipeline](https://aka.ms/mpt/configure-pipeline).
47 |
--------------------------------------------------------------------------------
/samples/get-started/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | # Starter pipeline
2 | # Start with a minimal pipeline that you can customize to build and deploy your code.
3 | # Add steps that build, run tests, deploy, and more:
4 | # https://aka.ms/yaml
5 |
6 | trigger:
7 | - none
8 |
9 | pool:
10 | vmImage: ubuntu-latest
11 |
12 | variables:
13 | "system.debug": false
14 |
15 | steps:
16 |
17 | - task: NodeTool@0
18 | inputs:
19 | versionSource: 'spec'
20 | versionSpec: '>18.x'
21 |
22 |
23 | - task: PowerShell@2
24 | enabled: true
25 | displayName: "Install dependencies"
26 | inputs:
27 | targetType: 'inline'
28 | script: 'npm ci'
29 | workingDirectory: '$(System.DefaultWorkingDirectory)/samples/get-started'
30 |
31 | - task: PowerShell@2
32 | enabled: true
33 | displayName: "Run Playwright tests"
34 | env:
35 | PLAYWRIGHT_SERVICE_ACCESS_TOKEN: $(Secret)
36 | inputs:
37 | targetType: 'inline'
38 | script: 'npx playwright test -c playwright.service.config.ts --workers=20'
39 | workingDirectory: '$(System.DefaultWorkingDirectory)/samples/get-started'
40 |
41 | - task: PublishPipelineArtifact@1
42 | inputs:
43 | targetPath: '$(System.DefaultWorkingDirectory)/samples/get-started/playwright-report/'
44 | artifact: 'Playwright tests'
45 | publishLocation: 'pipeline'
--------------------------------------------------------------------------------
/samples/get-started/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "get-started-sample",
3 | "version": "1.0.0",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "get-started-sample",
9 | "version": "1.0.0",
10 | "license": "MIT",
11 | "devDependencies": {
12 | "@azure/microsoft-playwright-testing": "^1.0.0-beta.3",
13 | "@playwright/test": "^1.47",
14 | "@types/node": "^18.19.68",
15 | "dotenv": "^16.4.5"
16 | }
17 | },
18 | "node_modules/@azure/abort-controller": {
19 | "version": "2.1.2",
20 | "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz",
21 | "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==",
22 | "dev": true,
23 | "license": "MIT",
24 | "dependencies": {
25 | "tslib": "^2.6.2"
26 | },
27 | "engines": {
28 | "node": ">=18.0.0"
29 | }
30 | },
31 | "node_modules/@azure/core-auth": {
32 | "version": "1.8.0",
33 | "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.8.0.tgz",
34 | "integrity": "sha512-YvFMowkXzLbXNM11yZtVLhUCmuG0ex7JKOH366ipjmHBhL3vpDcPAeWF+jf0X+jVXwFqo3UhsWUq4kH0ZPdu/g==",
35 | "dev": true,
36 | "license": "MIT",
37 | "dependencies": {
38 | "@azure/abort-controller": "^2.0.0",
39 | "@azure/core-util": "^1.1.0",
40 | "tslib": "^2.6.2"
41 | },
42 | "engines": {
43 | "node": ">=18.0.0"
44 | }
45 | },
46 | "node_modules/@azure/core-client": {
47 | "version": "1.9.2",
48 | "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.9.2.tgz",
49 | "integrity": "sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w==",
50 | "dev": true,
51 | "license": "MIT",
52 | "dependencies": {
53 | "@azure/abort-controller": "^2.0.0",
54 | "@azure/core-auth": "^1.4.0",
55 | "@azure/core-rest-pipeline": "^1.9.1",
56 | "@azure/core-tracing": "^1.0.0",
57 | "@azure/core-util": "^1.6.1",
58 | "@azure/logger": "^1.0.0",
59 | "tslib": "^2.6.2"
60 | },
61 | "engines": {
62 | "node": ">=18.0.0"
63 | }
64 | },
65 | "node_modules/@azure/core-http-compat": {
66 | "version": "2.1.2",
67 | "resolved": "https://registry.npmjs.org/@azure/core-http-compat/-/core-http-compat-2.1.2.tgz",
68 | "integrity": "sha512-5MnV1yqzZwgNLLjlizsU3QqOeQChkIXw781Fwh1xdAqJR5AA32IUaq6xv1BICJvfbHoa+JYcaij2HFkhLbNTJQ==",
69 | "dev": true,
70 | "license": "MIT",
71 | "dependencies": {
72 | "@azure/abort-controller": "^2.0.0",
73 | "@azure/core-client": "^1.3.0",
74 | "@azure/core-rest-pipeline": "^1.3.0"
75 | },
76 | "engines": {
77 | "node": ">=18.0.0"
78 | }
79 | },
80 | "node_modules/@azure/core-lro": {
81 | "version": "2.7.2",
82 | "resolved": "https://registry.npmjs.org/@azure/core-lro/-/core-lro-2.7.2.tgz",
83 | "integrity": "sha512-0YIpccoX8m/k00O7mDDMdJpbr6mf1yWo2dfmxt5A8XVZVVMz2SSKaEbMCeJRvgQ0IaSlqhjT47p4hVIRRy90xw==",
84 | "dev": true,
85 | "license": "MIT",
86 | "dependencies": {
87 | "@azure/abort-controller": "^2.0.0",
88 | "@azure/core-util": "^1.2.0",
89 | "@azure/logger": "^1.0.0",
90 | "tslib": "^2.6.2"
91 | },
92 | "engines": {
93 | "node": ">=18.0.0"
94 | }
95 | },
96 | "node_modules/@azure/core-paging": {
97 | "version": "1.6.2",
98 | "resolved": "https://registry.npmjs.org/@azure/core-paging/-/core-paging-1.6.2.tgz",
99 | "integrity": "sha512-YKWi9YuCU04B55h25cnOYZHxXYtEvQEbKST5vqRga7hWY9ydd3FZHdeQF8pyh+acWZvppw13M/LMGx0LABUVMA==",
100 | "dev": true,
101 | "license": "MIT",
102 | "dependencies": {
103 | "tslib": "^2.6.2"
104 | },
105 | "engines": {
106 | "node": ">=18.0.0"
107 | }
108 | },
109 | "node_modules/@azure/core-rest-pipeline": {
110 | "version": "1.17.0",
111 | "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.17.0.tgz",
112 | "integrity": "sha512-62Vv8nC+uPId3j86XJ0WI+sBf0jlqTqPUFCBNrGtlaUeQUIXWV/D8GE5A1d+Qx8H7OQojn2WguC8kChD6v0shA==",
113 | "dev": true,
114 | "license": "MIT",
115 | "dependencies": {
116 | "@azure/abort-controller": "^2.0.0",
117 | "@azure/core-auth": "^1.8.0",
118 | "@azure/core-tracing": "^1.0.1",
119 | "@azure/core-util": "^1.9.0",
120 | "@azure/logger": "^1.0.0",
121 | "http-proxy-agent": "^7.0.0",
122 | "https-proxy-agent": "^7.0.0",
123 | "tslib": "^2.6.2"
124 | },
125 | "engines": {
126 | "node": ">=18.0.0"
127 | }
128 | },
129 | "node_modules/@azure/core-tracing": {
130 | "version": "1.1.2",
131 | "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.1.2.tgz",
132 | "integrity": "sha512-dawW9ifvWAWmUm9/h+/UQ2jrdvjCJ7VJEuCJ6XVNudzcOwm53BFZH4Q845vjfgoUAM8ZxokvVNxNxAITc502YA==",
133 | "dev": true,
134 | "license": "MIT",
135 | "dependencies": {
136 | "tslib": "^2.6.2"
137 | },
138 | "engines": {
139 | "node": ">=18.0.0"
140 | }
141 | },
142 | "node_modules/@azure/core-util": {
143 | "version": "1.10.0",
144 | "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.10.0.tgz",
145 | "integrity": "sha512-dqLWQsh9Nro1YQU+405POVtXnwrIVqPyfUzc4zXCbThTg7+vNNaiMkwbX9AMXKyoFYFClxmB3s25ZFr3+jZkww==",
146 | "dev": true,
147 | "license": "MIT",
148 | "dependencies": {
149 | "@azure/abort-controller": "^2.0.0",
150 | "tslib": "^2.6.2"
151 | },
152 | "engines": {
153 | "node": ">=18.0.0"
154 | }
155 | },
156 | "node_modules/@azure/core-xml": {
157 | "version": "1.4.3",
158 | "resolved": "https://registry.npmjs.org/@azure/core-xml/-/core-xml-1.4.3.tgz",
159 | "integrity": "sha512-D6G7FEmDiTctPKuWegX2WTrS1enKZwqYwdKTO6ZN6JMigcCehlT0/CYl+zWpI9vQ9frwwp7GQT3/owaEXgnOsA==",
160 | "dev": true,
161 | "license": "MIT",
162 | "dependencies": {
163 | "fast-xml-parser": "^4.3.2",
164 | "tslib": "^2.6.2"
165 | },
166 | "engines": {
167 | "node": ">=18.0.0"
168 | }
169 | },
170 | "node_modules/@azure/identity": {
171 | "version": "4.4.1",
172 | "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.4.1.tgz",
173 | "integrity": "sha512-DwnG4cKFEM7S3T+9u05NstXU/HN0dk45kPOinUyNKsn5VWwpXd9sbPKEg6kgJzGbm1lMuhx9o31PVbCtM5sfBA==",
174 | "dev": true,
175 | "license": "MIT",
176 | "dependencies": {
177 | "@azure/abort-controller": "^1.0.0",
178 | "@azure/core-auth": "^1.5.0",
179 | "@azure/core-client": "^1.9.2",
180 | "@azure/core-rest-pipeline": "^1.1.0",
181 | "@azure/core-tracing": "^1.0.0",
182 | "@azure/core-util": "^1.3.0",
183 | "@azure/logger": "^1.0.0",
184 | "@azure/msal-browser": "^3.14.0",
185 | "@azure/msal-node": "^2.9.2",
186 | "events": "^3.0.0",
187 | "jws": "^4.0.0",
188 | "open": "^8.0.0",
189 | "stoppable": "^1.1.0",
190 | "tslib": "^2.2.0"
191 | },
192 | "engines": {
193 | "node": ">=18.0.0"
194 | }
195 | },
196 | "node_modules/@azure/identity/node_modules/@azure/abort-controller": {
197 | "version": "1.1.0",
198 | "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz",
199 | "integrity": "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==",
200 | "dev": true,
201 | "license": "MIT",
202 | "dependencies": {
203 | "tslib": "^2.2.0"
204 | },
205 | "engines": {
206 | "node": ">=12.0.0"
207 | }
208 | },
209 | "node_modules/@azure/logger": {
210 | "version": "1.1.4",
211 | "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.1.4.tgz",
212 | "integrity": "sha512-4IXXzcCdLdlXuCG+8UKEwLA1T1NHqUfanhXYHiQTn+6sfWCZXduqbtXDGceg3Ce5QxTGo7EqmbV6Bi+aqKuClQ==",
213 | "dev": true,
214 | "license": "MIT",
215 | "dependencies": {
216 | "tslib": "^2.6.2"
217 | },
218 | "engines": {
219 | "node": ">=18.0.0"
220 | }
221 | },
222 | "node_modules/@azure/microsoft-playwright-testing": {
223 | "version": "1.0.0-beta.3",
224 | "resolved": "https://registry.npmjs.org/@azure/microsoft-playwright-testing/-/microsoft-playwright-testing-1.0.0-beta.3.tgz",
225 | "integrity": "sha512-GsElI6E5M4cPvmKvdHEMnz0EAeC4jp0fQgPFzJvZVHST+hnMvZBc6z8a3c+WAvPD4MRgsxT6JuDlNu7SeoFlXg==",
226 | "dev": true,
227 | "license": "MIT",
228 | "dependencies": {
229 | "@azure/core-rest-pipeline": "^1.16.3",
230 | "@azure/identity": "^4.3.1",
231 | "@azure/logger": "^1.1.4",
232 | "@azure/storage-blob": "^12.15.0",
233 | "tslib": "^2.6.0"
234 | },
235 | "engines": {
236 | "node": ">=18.0.0"
237 | }
238 | },
239 | "node_modules/@azure/msal-browser": {
240 | "version": "3.23.0",
241 | "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-3.23.0.tgz",
242 | "integrity": "sha512-+QgdMvaeEpdtgRTD7AHHq9aw8uga7mXVHV1KshO1RQ2uI5B55xJ4aEpGlg/ga3H+0arEVcRfT4ZVmX7QLXiCVw==",
243 | "dev": true,
244 | "license": "MIT",
245 | "dependencies": {
246 | "@azure/msal-common": "14.14.2"
247 | },
248 | "engines": {
249 | "node": ">=0.8.0"
250 | }
251 | },
252 | "node_modules/@azure/msal-common": {
253 | "version": "14.14.2",
254 | "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.14.2.tgz",
255 | "integrity": "sha512-XV0P5kSNwDwCA/SjIxTe9mEAsKB0NqGNSuaVrkCCE2lAyBr/D6YtD80Vkdp4tjWnPFwjzkwldjr1xU/facOJog==",
256 | "dev": true,
257 | "license": "MIT",
258 | "engines": {
259 | "node": ">=0.8.0"
260 | }
261 | },
262 | "node_modules/@azure/msal-node": {
263 | "version": "2.13.1",
264 | "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.13.1.tgz",
265 | "integrity": "sha512-sijfzPNorKt6+9g1/miHwhj6Iapff4mPQx1azmmZExgzUROqWTM1o3ACyxDja0g47VpowFy/sxTM/WsuCyXTiw==",
266 | "dev": true,
267 | "license": "MIT",
268 | "dependencies": {
269 | "@azure/msal-common": "14.14.2",
270 | "jsonwebtoken": "^9.0.0",
271 | "uuid": "^8.3.0"
272 | },
273 | "engines": {
274 | "node": ">=16"
275 | }
276 | },
277 | "node_modules/@azure/storage-blob": {
278 | "version": "12.24.0",
279 | "resolved": "https://registry.npmjs.org/@azure/storage-blob/-/storage-blob-12.24.0.tgz",
280 | "integrity": "sha512-l8cmWM4C7RoNCBOImoFMxhTXe1Lr+8uQ/IgnhRNMpfoA9bAFWoLG4XrWm6O5rKXortreVQuD+fc1hbzWklOZbw==",
281 | "dev": true,
282 | "license": "MIT",
283 | "dependencies": {
284 | "@azure/abort-controller": "^1.0.0",
285 | "@azure/core-auth": "^1.4.0",
286 | "@azure/core-client": "^1.6.2",
287 | "@azure/core-http-compat": "^2.0.0",
288 | "@azure/core-lro": "^2.2.0",
289 | "@azure/core-paging": "^1.1.1",
290 | "@azure/core-rest-pipeline": "^1.10.1",
291 | "@azure/core-tracing": "^1.1.2",
292 | "@azure/core-util": "^1.6.1",
293 | "@azure/core-xml": "^1.3.2",
294 | "@azure/logger": "^1.0.0",
295 | "events": "^3.0.0",
296 | "tslib": "^2.2.0"
297 | },
298 | "engines": {
299 | "node": ">=18.0.0"
300 | }
301 | },
302 | "node_modules/@azure/storage-blob/node_modules/@azure/abort-controller": {
303 | "version": "1.1.0",
304 | "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-1.1.0.tgz",
305 | "integrity": "sha512-TrRLIoSQVzfAJX9H1JeFjzAoDGcoK1IYX1UImfceTZpsyYfWr09Ss1aHW1y5TrrR3iq6RZLBwJ3E24uwPhwahw==",
306 | "dev": true,
307 | "license": "MIT",
308 | "dependencies": {
309 | "tslib": "^2.2.0"
310 | },
311 | "engines": {
312 | "node": ">=12.0.0"
313 | }
314 | },
315 | "node_modules/@playwright/test": {
316 | "version": "1.47.1",
317 | "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.47.1.tgz",
318 | "integrity": "sha512-dbWpcNQZ5nj16m+A5UNScYx7HX5trIy7g4phrcitn+Nk83S32EBX/CLU4hiF4RGKX/yRc93AAqtfaXB7JWBd4Q==",
319 | "dev": true,
320 | "license": "Apache-2.0",
321 | "dependencies": {
322 | "playwright": "1.47.1"
323 | },
324 | "bin": {
325 | "playwright": "cli.js"
326 | },
327 | "engines": {
328 | "node": ">=18"
329 | }
330 | },
331 | "node_modules/@types/node": {
332 | "version": "18.19.68",
333 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.68.tgz",
334 | "integrity": "sha512-QGtpFH1vB99ZmTa63K4/FU8twThj4fuVSBkGddTp7uIL/cuoLWIUSL2RcOaigBhfR+hg5pgGkBnkoOxrTVBMKw==",
335 | "dev": true,
336 | "license": "MIT",
337 | "dependencies": {
338 | "undici-types": "~5.26.4"
339 | }
340 | },
341 | "node_modules/agent-base": {
342 | "version": "7.1.1",
343 | "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
344 | "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
345 | "dev": true,
346 | "license": "MIT",
347 | "dependencies": {
348 | "debug": "^4.3.4"
349 | },
350 | "engines": {
351 | "node": ">= 14"
352 | }
353 | },
354 | "node_modules/buffer-equal-constant-time": {
355 | "version": "1.0.1",
356 | "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
357 | "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
358 | "dev": true,
359 | "license": "BSD-3-Clause"
360 | },
361 | "node_modules/debug": {
362 | "version": "4.3.7",
363 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
364 | "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
365 | "dev": true,
366 | "license": "MIT",
367 | "dependencies": {
368 | "ms": "^2.1.3"
369 | },
370 | "engines": {
371 | "node": ">=6.0"
372 | },
373 | "peerDependenciesMeta": {
374 | "supports-color": {
375 | "optional": true
376 | }
377 | }
378 | },
379 | "node_modules/define-lazy-prop": {
380 | "version": "2.0.0",
381 | "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz",
382 | "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==",
383 | "dev": true,
384 | "license": "MIT",
385 | "engines": {
386 | "node": ">=8"
387 | }
388 | },
389 | "node_modules/dotenv": {
390 | "version": "16.4.5",
391 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
392 | "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==",
393 | "dev": true,
394 | "license": "BSD-2-Clause",
395 | "engines": {
396 | "node": ">=12"
397 | },
398 | "funding": {
399 | "url": "https://dotenvx.com"
400 | }
401 | },
402 | "node_modules/ecdsa-sig-formatter": {
403 | "version": "1.0.11",
404 | "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
405 | "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
406 | "dev": true,
407 | "license": "Apache-2.0",
408 | "dependencies": {
409 | "safe-buffer": "^5.0.1"
410 | }
411 | },
412 | "node_modules/events": {
413 | "version": "3.3.0",
414 | "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
415 | "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
416 | "dev": true,
417 | "license": "MIT",
418 | "engines": {
419 | "node": ">=0.8.x"
420 | }
421 | },
422 | "node_modules/fast-xml-parser": {
423 | "version": "4.5.0",
424 | "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.0.tgz",
425 | "integrity": "sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==",
426 | "dev": true,
427 | "funding": [
428 | {
429 | "type": "github",
430 | "url": "https://github.com/sponsors/NaturalIntelligence"
431 | },
432 | {
433 | "type": "paypal",
434 | "url": "https://paypal.me/naturalintelligence"
435 | }
436 | ],
437 | "license": "MIT",
438 | "dependencies": {
439 | "strnum": "^1.0.5"
440 | },
441 | "bin": {
442 | "fxparser": "src/cli/cli.js"
443 | }
444 | },
445 | "node_modules/fsevents": {
446 | "version": "2.3.2",
447 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
448 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
449 | "dev": true,
450 | "hasInstallScript": true,
451 | "license": "MIT",
452 | "optional": true,
453 | "os": [
454 | "darwin"
455 | ],
456 | "engines": {
457 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
458 | }
459 | },
460 | "node_modules/http-proxy-agent": {
461 | "version": "7.0.2",
462 | "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
463 | "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
464 | "dev": true,
465 | "license": "MIT",
466 | "dependencies": {
467 | "agent-base": "^7.1.0",
468 | "debug": "^4.3.4"
469 | },
470 | "engines": {
471 | "node": ">= 14"
472 | }
473 | },
474 | "node_modules/https-proxy-agent": {
475 | "version": "7.0.5",
476 | "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz",
477 | "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==",
478 | "dev": true,
479 | "license": "MIT",
480 | "dependencies": {
481 | "agent-base": "^7.0.2",
482 | "debug": "4"
483 | },
484 | "engines": {
485 | "node": ">= 14"
486 | }
487 | },
488 | "node_modules/is-docker": {
489 | "version": "2.2.1",
490 | "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz",
491 | "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==",
492 | "dev": true,
493 | "license": "MIT",
494 | "bin": {
495 | "is-docker": "cli.js"
496 | },
497 | "engines": {
498 | "node": ">=8"
499 | },
500 | "funding": {
501 | "url": "https://github.com/sponsors/sindresorhus"
502 | }
503 | },
504 | "node_modules/is-wsl": {
505 | "version": "2.2.0",
506 | "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz",
507 | "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==",
508 | "dev": true,
509 | "license": "MIT",
510 | "dependencies": {
511 | "is-docker": "^2.0.0"
512 | },
513 | "engines": {
514 | "node": ">=8"
515 | }
516 | },
517 | "node_modules/jsonwebtoken": {
518 | "version": "9.0.2",
519 | "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
520 | "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
521 | "dev": true,
522 | "license": "MIT",
523 | "dependencies": {
524 | "jws": "^3.2.2",
525 | "lodash.includes": "^4.3.0",
526 | "lodash.isboolean": "^3.0.3",
527 | "lodash.isinteger": "^4.0.4",
528 | "lodash.isnumber": "^3.0.3",
529 | "lodash.isplainobject": "^4.0.6",
530 | "lodash.isstring": "^4.0.1",
531 | "lodash.once": "^4.0.0",
532 | "ms": "^2.1.1",
533 | "semver": "^7.5.4"
534 | },
535 | "engines": {
536 | "node": ">=12",
537 | "npm": ">=6"
538 | }
539 | },
540 | "node_modules/jsonwebtoken/node_modules/jwa": {
541 | "version": "1.4.1",
542 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
543 | "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
544 | "dev": true,
545 | "license": "MIT",
546 | "dependencies": {
547 | "buffer-equal-constant-time": "1.0.1",
548 | "ecdsa-sig-formatter": "1.0.11",
549 | "safe-buffer": "^5.0.1"
550 | }
551 | },
552 | "node_modules/jsonwebtoken/node_modules/jws": {
553 | "version": "3.2.2",
554 | "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
555 | "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
556 | "dev": true,
557 | "license": "MIT",
558 | "dependencies": {
559 | "jwa": "^1.4.1",
560 | "safe-buffer": "^5.0.1"
561 | }
562 | },
563 | "node_modules/jwa": {
564 | "version": "2.0.0",
565 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz",
566 | "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==",
567 | "dev": true,
568 | "license": "MIT",
569 | "dependencies": {
570 | "buffer-equal-constant-time": "1.0.1",
571 | "ecdsa-sig-formatter": "1.0.11",
572 | "safe-buffer": "^5.0.1"
573 | }
574 | },
575 | "node_modules/jws": {
576 | "version": "4.0.0",
577 | "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz",
578 | "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==",
579 | "dev": true,
580 | "license": "MIT",
581 | "dependencies": {
582 | "jwa": "^2.0.0",
583 | "safe-buffer": "^5.0.1"
584 | }
585 | },
586 | "node_modules/lodash.includes": {
587 | "version": "4.3.0",
588 | "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
589 | "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
590 | "dev": true,
591 | "license": "MIT"
592 | },
593 | "node_modules/lodash.isboolean": {
594 | "version": "3.0.3",
595 | "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
596 | "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
597 | "dev": true,
598 | "license": "MIT"
599 | },
600 | "node_modules/lodash.isinteger": {
601 | "version": "4.0.4",
602 | "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
603 | "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
604 | "dev": true,
605 | "license": "MIT"
606 | },
607 | "node_modules/lodash.isnumber": {
608 | "version": "3.0.3",
609 | "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
610 | "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
611 | "dev": true,
612 | "license": "MIT"
613 | },
614 | "node_modules/lodash.isplainobject": {
615 | "version": "4.0.6",
616 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
617 | "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
618 | "dev": true,
619 | "license": "MIT"
620 | },
621 | "node_modules/lodash.isstring": {
622 | "version": "4.0.1",
623 | "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
624 | "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
625 | "dev": true,
626 | "license": "MIT"
627 | },
628 | "node_modules/lodash.once": {
629 | "version": "4.1.1",
630 | "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
631 | "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
632 | "dev": true,
633 | "license": "MIT"
634 | },
635 | "node_modules/ms": {
636 | "version": "2.1.3",
637 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
638 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
639 | "dev": true,
640 | "license": "MIT"
641 | },
642 | "node_modules/open": {
643 | "version": "8.4.2",
644 | "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
645 | "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==",
646 | "dev": true,
647 | "license": "MIT",
648 | "dependencies": {
649 | "define-lazy-prop": "^2.0.0",
650 | "is-docker": "^2.1.1",
651 | "is-wsl": "^2.2.0"
652 | },
653 | "engines": {
654 | "node": ">=12"
655 | },
656 | "funding": {
657 | "url": "https://github.com/sponsors/sindresorhus"
658 | }
659 | },
660 | "node_modules/playwright": {
661 | "version": "1.47.1",
662 | "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.47.1.tgz",
663 | "integrity": "sha512-SUEKi6947IqYbKxRiqnbUobVZY4bF1uu+ZnZNJX9DfU1tlf2UhWfvVjLf01pQx9URsOr18bFVUKXmanYWhbfkw==",
664 | "dev": true,
665 | "license": "Apache-2.0",
666 | "dependencies": {
667 | "playwright-core": "1.47.1"
668 | },
669 | "bin": {
670 | "playwright": "cli.js"
671 | },
672 | "engines": {
673 | "node": ">=18"
674 | },
675 | "optionalDependencies": {
676 | "fsevents": "2.3.2"
677 | }
678 | },
679 | "node_modules/playwright-core": {
680 | "version": "1.47.1",
681 | "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.47.1.tgz",
682 | "integrity": "sha512-i1iyJdLftqtt51mEk6AhYFaAJCDx0xQ/O5NU8EKaWFgMjItPVma542Nh/Aq8aLCjIJSzjaiEQGW/nyqLkGF1OQ==",
683 | "dev": true,
684 | "license": "Apache-2.0",
685 | "bin": {
686 | "playwright-core": "cli.js"
687 | },
688 | "engines": {
689 | "node": ">=18"
690 | }
691 | },
692 | "node_modules/safe-buffer": {
693 | "version": "5.2.1",
694 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
695 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
696 | "dev": true,
697 | "funding": [
698 | {
699 | "type": "github",
700 | "url": "https://github.com/sponsors/feross"
701 | },
702 | {
703 | "type": "patreon",
704 | "url": "https://www.patreon.com/feross"
705 | },
706 | {
707 | "type": "consulting",
708 | "url": "https://feross.org/support"
709 | }
710 | ],
711 | "license": "MIT"
712 | },
713 | "node_modules/semver": {
714 | "version": "7.6.3",
715 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
716 | "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
717 | "dev": true,
718 | "license": "ISC",
719 | "bin": {
720 | "semver": "bin/semver.js"
721 | },
722 | "engines": {
723 | "node": ">=10"
724 | }
725 | },
726 | "node_modules/stoppable": {
727 | "version": "1.1.0",
728 | "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz",
729 | "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==",
730 | "dev": true,
731 | "license": "MIT",
732 | "engines": {
733 | "node": ">=4",
734 | "npm": ">=6"
735 | }
736 | },
737 | "node_modules/strnum": {
738 | "version": "1.0.5",
739 | "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz",
740 | "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==",
741 | "dev": true,
742 | "license": "MIT"
743 | },
744 | "node_modules/tslib": {
745 | "version": "2.7.0",
746 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz",
747 | "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==",
748 | "dev": true,
749 | "license": "0BSD"
750 | },
751 | "node_modules/undici-types": {
752 | "version": "5.26.5",
753 | "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
754 | "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
755 | "dev": true,
756 | "license": "MIT"
757 | },
758 | "node_modules/uuid": {
759 | "version": "8.3.2",
760 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
761 | "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
762 | "dev": true,
763 | "license": "MIT",
764 | "bin": {
765 | "uuid": "dist/bin/uuid"
766 | }
767 | }
768 | }
769 | }
770 |
--------------------------------------------------------------------------------
/samples/get-started/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "get-started-sample",
3 | "description": "Playwright Service get started sample",
4 | "version": "1.0.0",
5 | "scripts": {
6 | "test": "npx playwright test -c playwright.service.config.ts --workers=20",
7 | "test-local": "npx playwright test"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "MIT",
12 | "devDependencies": {
13 | "@azure/microsoft-playwright-testing": "^1.0.0-beta.3",
14 | "@playwright/test": "^1.47",
15 | "@types/node": "^18.19.68",
16 | "dotenv": "^16.4.5"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/samples/get-started/playwright.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig, devices } from '@playwright/test';
2 |
3 | export default defineConfig({
4 | testDir: './tests',
5 | fullyParallel: true,
6 | forbidOnly: !!process.env.CI,
7 | retries: process.env.CI ? 2 : 0,
8 | workers: process.env.CI ? 1 : undefined,
9 | reporter: 'html',
10 | use: {
11 | trace: 'on-first-retry',
12 | },
13 | projects: [
14 | {
15 | name: 'chromium',
16 | use: { ...devices['Desktop Chrome'] },
17 | },
18 |
19 | {
20 | name: 'firefox',
21 | use: { ...devices['Desktop Firefox'] },
22 | },
23 |
24 | {
25 | name: 'webkit',
26 | use: { ...devices['Desktop Safari'] },
27 | },
28 | ],
29 | });
30 |
--------------------------------------------------------------------------------
/samples/get-started/playwright.service.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from '@playwright/test';
2 | import { getServiceConfig, ServiceOS } from '@azure/microsoft-playwright-testing';
3 | import config from './playwright.config';
4 |
5 | /* Learn more about service configuration at https://aka.ms/mpt/config */
6 | export default defineConfig(
7 | config,
8 | getServiceConfig(config, {
9 | exposeNetwork: '',
10 | timeout: 30000,
11 | os: ServiceOS.LINUX,
12 | useCloudHostedBrowsers: true
13 | }),
14 | {
15 | /*
16 | Playwright Testing service reporter is added by default.
17 | This will override any reporter options specified in the base playwright config.
18 | If you are using more reporters, please update your configuration accordingly.
19 | */
20 | reporter: [['list'], ['@azure/microsoft-playwright-testing/reporter']],
21 | }
22 | );
23 |
--------------------------------------------------------------------------------
/samples/get-started/tests/example.spec.ts:
--------------------------------------------------------------------------------
1 | import { test, expect } from '@playwright/test';
2 |
3 | // This sample simulates a larger test suite
4 | const TEST_ITERATIONS = parseInt(process.env.TEST_ITERATIONS || "100");
5 | for (var i = 0; i < TEST_ITERATIONS; i++) {
6 |
7 | test('has title ' + i, async ({ page }) => {
8 | await page.goto('https://playwright.dev/');
9 |
10 | // Expect a title "to contain" a substring.
11 | await expect(page).toHaveTitle(/Playwright/);
12 | });
13 |
14 | test('get started link ' + i, async ({ page }) => {
15 | await page.goto('https://playwright.dev/');
16 |
17 | // Click the get started link.
18 | await page.getByRole('link', { name: 'Get started' }).click();
19 |
20 | // Expects the URL to contain intro.
21 | await expect(page).toHaveURL(/.*intro/);
22 | });
23 |
24 | }
25 |
--------------------------------------------------------------------------------