diff --git a/e2e-playwright/css/own.css b/e2e-playwright/css/own.css new file mode 100644 index 0000000..b90b389 --- /dev/null +++ b/e2e-playwright/css/own.css @@ -0,0 +1,111 @@ +.devon.reveal .title-with-image img { + margin-right: 0.5em; +} + +.reveal h1.no_upper, +.reveal h2.no_upper, +.reveal h3.no_upper, +.reveal h4.no_upper, +.reveal h5.no_upper, +.reveal h6.no_upper { + text-transform: none; +} + +.reveal section img { + border: none; + box-shadow: none; +} + +.reveal section img.middle { + vertical-align : middle; +} + +div.margin_top_30 { + margin-top: 30px; +} + +h1.highlight, h2.highlight, h3.highlight, p.highlight, span.highlight { + color: #71e9f4; +} + +div.column { + display: inline-block; + margin-right: 40px; +} + +p.title_image img.white_solid_border { + border: 4px solid #ffffff; +} + +p.justify_text { + text-align: justify; +} + +p.align_right { + text-align: right; +} + +.reveal pre { + border: 3px white solid; +} + +.reveal p { + margin: 0; +} + +.reveal #js-engine { + height: 560px; +} + +.reveal .title_image img { + background: transparent; + margin: 0 40px; +} + +.reveal section pre { + width: 100%; +} + +.reveal section .list-style-none { + list-style: none +} + +.reveal section .margin-top-40 { + margin-top: 40px; +} + +html.img-center-fill div.slide-background.present { + background-position: center; + background-size: contain; +} + +.reveal section .text-align-left { + text-align: left; +} + +.reveal section .font-style-italic { + font-style: italic; +} + +.reveal section div.side-by-side { + width: 960px; +} + +.reveal section div.side-by-side div { + width: 45%; + display: inline-block; + vertical-align: top; +} + +.reveal section pre code.code-without-max-height { + max-height: unset; +} + +.reveal section .inline-block { + display: inline-block; + vertical-align: top; +} + +.reveal section .margin-top-70 { + margin-top: 70px; +} \ No newline at end of file diff --git a/e2e-playwright/img/e2e-testing-compare.png b/e2e-playwright/img/e2e-testing-compare.png new file mode 100644 index 0000000..8dbd5c5 Binary files /dev/null and b/e2e-playwright/img/e2e-testing-compare.png differ diff --git a/e2e-playwright/img/playwright-ui-mode.png b/e2e-playwright/img/playwright-ui-mode.png new file mode 100644 index 0000000..c2b0b88 Binary files /dev/null and b/e2e-playwright/img/playwright-ui-mode.png differ diff --git a/e2e-playwright/index.html b/e2e-playwright/index.html new file mode 100644 index 0000000..29d3510 --- /dev/null +++ b/e2e-playwright/index.html @@ -0,0 +1,196 @@ + + + + + + + + E2E Testing with Playwright + + + + + + + + + + + + + + + + + + + +
+
+
+

E2E-TESTING USING PLAYWRIGHT

+

Docs

+
+
+

Why test end-to-end?

+

We test...

+
    +
  • to ensure our application works within the target eco-system.
  • +
  • automated to get quick and reliable feedback.
  • +
  • to detect breaking features as soon as possible.
  • +
  • to ensure the best quality.
  • +
+
+
+

End-to-end testing our Angular applications

+

+ Protractor is deprecated as of May 2021 due to... +

+
    +
  • outdated Selenium based testing.
  • +
  • many modern alternatives exist.
  • +
+
+
+

Playwright as an alternative

+ Compare Web Testing +

"Playwright is a framework for Web Testing and Automation. It allows testing Chromium, Firefox and WebKit with a single API."

+
+

Playwright +

+
+
+
+

It is just another node module...

+

+yarn create playwright
+            
+
+
+

...which comes with everything you need to start testing!

+ Playwright start page +
+
+

You can visit your app...

+

+await page.goto('/movies');
+            
+ +
+
+

...interact with elements...

+

+// click on a fancy button
+await page.getByRole('button', { name: 'Fancy Button' }).click();
+// clear and type into a fancy input
+await page.getByLabel('Fancy Input').fill('Important stuff');
+            
+ +
+
+

...make assertions...

+

+// check whether the input value is something
+await expect(page.getByLabel('Fancy Input')).toContainText('Important stuff');
+            
+ +
+
+

...and even mock or intercept backend calls!

+

+// mock backend calls
+await page.route('/services/rest/movies', async route => {
+  const json = [{ name: 'Titanic', id: 21 }];
+  await route.fulfill({ json });
+});
+
+// intercept a call and work with the response
+const movies = await request.get(`/services/rest/movies`);
+
+// wait for a request before moving on
+await page.waitForResponse('/services/rest/movies'/);
+            
+ +
+
+

The test structure looks familiar!

+

+test.describe('Movie Page', () => {
+  let moviesPage: MoviesPage;
+
+  test.beforeEach(() => {
+    moviesPage = new MoviesPage();
+  });
+
+  test('should create a new movie', async () => {
+    // goto the movie overview
+    await moviesPage.goto();
+
+    // do stuff
+    await moviesPage.clickAddButton();
+    // do something to add a new movie...
+  });
+});
+            
+ +
+
+

Some best practices:

+
    +
  • Make tests as isolated as possible (i.e. with beforeEach, Page Object Models, Fixture)
  • +
  • Use locators with chaining/filtering and prefer user-facing attributes to XPath or CSS selectors
  • +
  • Use web first assertions because it will wait until the expected condition is met.
  • +
  • do not store the result of a chainable command in a variable.
  • +
  • use as many assertions as needed. It's not unit testing.
  • +
+ + +
+
+
+ + + + + + + + \ No newline at end of file diff --git a/exercises/ngrx.html b/exercises/ngrx.html index 0f9ad52..8c1d2e4 100644 --- a/exercises/ngrx.html +++ b/exercises/ngrx.html @@ -66,7 +66,7 @@

ngrx basics

Basic Setup


-                    // Input: 5, 3, 3, 11, 7, 7, 19
+                    // Input: 5, 3, 3, 11, 7, 7, 3, 3, 3, 19
                     filter( value => value > 10)  // 11, 19
                     take( 5 )               // 5, 3, 3, 11, 7
-                    distinctUntilChanged()  // 5, 3, 11, 7, 19
+                    distinctUntilChanged()  // 5, 3, 11, 7, 3, 19