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
+
+ "Playwright is a framework for Web Testing and Automation. It allows testing Chromium, Firefox and WebKit with a single API."
+
+
+
+ It is just another node module...
+
+yarn create playwright
+
+
+
+ ...which comes with everything you need to start testing!
+
+
+
+ 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
ng new ngrx-exercise
+ ng new ngrx-exercise --standalone false
Add @ngrx/store
and @ngrx/store-devtools
to the dependencies with npm/yarn
Download the Redux Devtools Extension for
diff --git a/ng-advanced/rxjs/index.html b/ng-advanced/rxjs/index.html
index b874c14..d221a11 100644
--- a/ng-advanced/rxjs/index.html
+++ b/ng-advanced/rxjs/index.html
@@ -136,10 +136,10 @@ RxJS - Level 1: Basic Operators
Simple selection and filtering
- // 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
@@ -451,7 +451,7 @@ RxJS - Level 8: Error Handling
// j k l x4|
catchError(() => of('z'))
retry( 2 )
- retry({ delay: (error) => error === x1 : of(error) : throwError(() => error) })
+ retry({ delay: (error) => error === x1 ? of(error) : throwError(() => error) })
Note: xN is an error
@@ -472,7 +472,7 @@ RxJS - Level 8: Error Handling (Solution)
// a b c z
retry( 2 )
// a b c d e f g h i x3
- retry({ delay: (error) => error === x1 : of(error) : throwError(() => error) })
+ retry({ delay: (error) => error === x1 ? of(error) : throwError(() => error) })
// a b c d e f x2