Teraz Ty: Kolejny test pulpitu

TIP: Ta lekcja jest częścią rozwijanego Programu Testy Automatyczne z Playwright 🎭

Dodatkowe materiały

Link do testowanej strony

Twoje zadanie polega na przygotowanie testu automatycznego dla operacji doładowania telefonu na stronie Pulpit.

Możesz samodzielnie utworzyć ten test (wzorując się mocno na poprzednim teście) lub wspomóc się poniższymi wskazówkami.

Dokładne kroki:

  1. Wykonaj manualny test doładowania telefonu
  2. Dodaj nowy test do pulpit.spec.ts
  3. Sugerowana nazwa nowego testu: successful mobile top-up
  4. Użyj codegen do nagrania testu i wygenerowania kodu
    • Pomiń nagrywanie logowania
    • Na stronie Pulpit przejdź do widoku doładowanie telefonu
    • Wybierz numer telefonu (pierwszy z listy), kwotę 50 i zaznacz checkbox
    • Kliknięciu przycisk doładuj telefon oraz zaakceptuj okno z podsumowaniem operacji
    • Zweryfikuj tekst wiadomości, możesz skorzystać z istniejącego kodu w innym teście

    Wklej uzyskany kod do nowo przygotowanego testu

  5. Pamiętaj o dodaniu odpowiedniej asercji dla wiadomości
  6. Usuń lub zakomentuj nadmiarowy kod np: niepotrzebne akcje z click()
  7. Sprawdź swój test – pamiętaj o opcji only
  8. Celowo uszkodź asercję, tak aby test zakończył się niepowodzeniem i uruchom ponownie test – czy wyniki jakie otrzymałeś są czytelne?
  9. Następnie napraw test i uruchom wszystkie testy razem
Tip 1 - jak wystartować?
Na początku możesz skorzystać z narzędzia codegen, aby nagrać test 😉
Tip 2 - szukanie elementów
Możesz wykorzystać DevTools w przeglądarce, aby wyszukać potrzebne Ci elementy.

Aby wyszukać elementy w przeglądarce za pomocą selektorów CSS otwórz narzędzia developerskie (DevTools). Następnie otwórz konsolę i użyj następującej konstrukcji:

$$(‘selektor CSS’)

Więcej o wyszukiwaniu elementów znajdziesz w naszym bonusie:

Tip 3 - przerywanie testu
Jeśli zawiesił Ci się proces w konsoli, albo chcesz przerwać testy, to możesz użyć skrótu CTRL + C, aby przerwać działający proces.
Tip 4 - asercja
Pamiętaj, aby po teście dodac asercję, która sprawdzi komunikat widoczny na stronie banku, czyli np.:

        await expect(page.locator('#show_messages')).toHaveText('Doładowanie wykonane! 50,00PLN na numer 503 xxx xxx')
      });

11 komentarzy

  1. Hej hej,
    Pytanie organizacyjne 🙂
    Czy do zaznaczania checkbox’a lepiej używać .click() – jak sugeruje Playwright,
    Czy lepiej do checkboxó używać .check()/.uncheck() ??
    Oficjalnie obie metody działają – Playwright sugeruje click() bo klikamy aby zaznaczyć element ale metoda check również zaznacza checkbox i na pewno nie będzie błędu jak przez nieuwagę kilkukrotnie zcheckujemy checkboxa – bo do jego odznaczania służy metoda .uncheck()

    Jeżeli chodzi o clicka to wielokrotne kliknięcie może zostawić usuniety checkbox jak poniżej:

      await page.getByLabel('zapoznałem się z regulaminem').click();
      await page.getByLabel('zapoznałem się z regulaminem').click();
      await page.getByLabel('zapoznałem się z regulaminem').click();
      await page.getByLabel('zapoznałem się z regulaminem').click();
      await page.getByLabel('zapoznałem się z regulaminem').click();
      await page.getByLabel('zapoznałem się z regulaminem').click();
      await page.getByLabel('zapoznałem się z regulaminem').click();
      await page.getByLabel('zapoznałem się z regulaminem').click();
      await page.getByLabel('zapoznałem się z regulaminem').click();
      await page.getByLabel('zapoznałem się z regulaminem').click();
      await page.getByLabel('zapoznałem się z regulaminem').click(); 
    Nie zmienia się komunikat po pierszym kliknięciu i parzaysta liczba kliknięć zostawi checkbox'a odznaczonego
    

    Co do .check()/uncheck()

     await page.locator('#uniform-widget_1_topup_agreement span').check();
     await page.waitForTimeout(2000);  <-- tylko dla sprawdzenia zachowania checkboxa
    await page.locator('#uniform-widget_1_topup_agreement span').check();
    await page.locator('#uniform-widget_1_topup_agreement span').uncheck();
    await page.waitForTimeout(2000); <-- tylko dla sprawdzenia zachowania checkboxa
    await page.locator('#uniform-widget_1_topup_agreement span').check();
    

    To checkować możemy wiele razy a checkbox zawsze będzie zcheckowany – do jego odznaczenia potrzebujemy użyć metody .uncheck() <– czyli z użytkowego punktu widzenia do checkbox.ów chyba lepiej używać .check'a niż click'a tak ??
    Czy są jakieś przesłanki aby bezgranicznie ufać 😉 codegen'owi playwrightowemu ??

    Pozdrawiam i dzięki z góry za odpowiedź/potwierdzenie,
    Jakub K

    Avatar Jakub Kruszyński
    1. Fajna analiza i pytanie. Obie metody zachowają się podobnie i bardziej bym się zastanowił co chcemy testować.

      Jeśli skupiamy się typowo na testach checkbox to wtedy można użyć metod click() i sprawdzać asercjami np: expect(locator).toBeChecked(). Czyli weryfikujemy czy checkbox ma dany stan przy danych warunkach.

      Gdy jednak checkbox to tylko element większych testów będzie zdecydowanie łatwiej czytać testy gdy widzimy ustawienie pożądanego stanu check/uncheck gdyż sam click() może nam tej informacji nie dać.

      Podsumowując – w standardowych testach raczej bym się skłaniał do opcji check() i codegen traktował jako pomoc ale nie wyrocznię 😀

      Pozdr

      Przemek Przemek
  2. Też “udało mi się” raz uzyskać ten błąd z asercją dot. treści wiadomości! 🙂
    Expected string: “Doładowanie wykonane! 50,00PLN na numer 500 xxx xxx”
    Received string: “Brak wiadomości”
    Przy innych próbach test przechodził. Ot, ciekawostka!

    Avatar Slawomir Nowodworski
    1. Tak właśnie działa ta aplikacja, że nieraz tak może się stać i dobrze bo pokazuje to realne problemy z testami😉.

      Aby temu zapobiec można pokusić się o zwiększenie timeouta w playwright.config.ts dla expect do 10 sekund:

      timeout: 10000

      Jak zawsze zachęcam do testów 🤩

      Przemek Barański Przemek Barański
      1. Mam ten sam problem co Sławomir, niestety nie mogę znaleźć timeout w pliku playwright.config.ts, podejrzewam, że coś ulgło zmianie w samym PW i w materiałach do lekcji. Jak mogę zmienić timeout na 10000?

        import { defineConfig, devices } from '@playwright/test';
        
        /**
         * Read environment variables from file.
         * https://github.com/motdotla/dotenv
         */
        // require('dotenv').config();
        
        /**
         * See https://playwright.dev/docs/test-configuration.
         */
        export default defineConfig({
          testDir: './tests',
          /* Run tests in files in parallel */
          fullyParallel: true,
          /* Fail the build on CI if you accidentally left test.only in the source code. */
          forbidOnly: !!process.env.CI,
          /* Retry on CI only */
          retries: process.env.CI ? 2 : 0,
          /* Opt out of parallel tests on CI. */
          workers: process.env.CI ? 1 : undefined,
          /* Reporter to use. See https://playwright.dev/docs/test-reporters */
          reporter: 'html',
          /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
          use: {
            /* Base URL to use in actions like `await page.goto('/')`. */
            // baseURL: 'http://127.0.0.1:3000',
        
            /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
            trace: 'on-first-retry',
          },
        
          /* Configure projects for major browsers */
          projects: [
            {
              name: 'chromium',
              use: { ...devices['Desktop Chrome'] },
            },
        
            // {
            //   name: 'firefox',
            //   use: { ...devices['Desktop Firefox'] },
            // },
        
            // {
            //   name: 'webkit',
            //   use: { ...devices['Desktop Safari'] },
            // },
        
            /* Test against mobile viewports. */
            // {
            //   name: 'Mobile Chrome',
            //   use: { ...devices['Pixel 5'] },
            // },
            // {
            //   name: 'Mobile Safari',
            //   use: { ...devices['iPhone 12'] },
            // },
        
            /* Test against branded browsers. */
            // {
            //   name: 'Microsoft Edge',
            //   use: { ...devices['Desktop Edge'], channel: 'msedge' },
            // },
            // {
            //   name: 'Google Chrome',
            //   use: { ...devices['Desktop Chrome'], channel: 'chrome' },
            // },
          ],
        
          /* Run your local dev server before starting the tests */
          // webServer: {
          //   command: 'npm run start',
          //   url: 'http://127.0.0.1:3000',
          //   reuseExistingServer: !process.env.CI,
          // },
        });
        
        Avatar Franciszek Klocek
        1. Ople timeout jest opcjonalne (domyślna wartość to 5 sekund
          https://playwright.dev/docs/test-timeouts

          Aby go ustawić musisz dodać w swojej konfiguracji nowy blok expect:

          export default defineConfig({
            testDir: './tests',
            expect: {
              /**
               * Maximum time expect() should wait for the condition to be met.
               * For example in `await expect(locator).toHaveText();`
               */
              timeout: 10000,
            },
          ...
          

          Sprawdź i proszę daj znać czy zadziałało 😉

          Krzysiek Kijas Krzysiek Kijas
          1. Dzięki, działa, ale jednak problem był po mojej stronie 😀 Na końcu w asercji miałem

            await expect (page.getByTestId(‘#message-text’)).toHaveText(‘Doładowanie wykonane! 50,00PLN na numer 500 xxx xxx’);

            Sprawdziłem w devtoolsach i przypomniałem sobie, że to jest data-testid a nie id (wtedy hash jest ok), więc wyrzuciłem hash i poszło. Ale dzięki za komentarz bo i tak miałem pytać o ten timeout, brakowało mi go przy innych testach 🙂

            Avatar Franciszek Klocek
  3. hejka! 🙂
    znacie sposoby jak uniknąć błędu ‘Execution context was destroyed, most likely because of a navigation’ ?
    Niestety mamy takie testy, które strony zawarte w testach są zależne od siebie..

    Słonecznego dnia! 🙂

    Avatar Karolina
    1. Bardzo dobre pytanie Karolina!
      Będziemy ten temat omawiać w przyszłości. Na teraz pamiętajmy, że Playwright wykonuje wszystkie testy niezależnie. No i pojawia się problem z testami zależnymi. Można to ograć to posiadając jeden test z wieloma krokami:

      import { test, expect } from '@playwright/test';
      
      test.describe('Pulpit tests', () => {
          test('quick payment with correct data', async ({ page }) => {
            
            await test.step('Login to demobank', async() => {
              await page.goto('https://demo-bank.vercel.app/');
              await page.getByTestId('login-input').fill('testerLO');
              await page.getByTestId('password-input').fill('password');
              await page.getByTestId('login-button').click();
            });
      
            await test.step('Preform tranfer', async() => {
              await page.locator('#widget_1_transfer_receiver').selectOption('2');
              await page.locator('#widget_1_transfer_amount').fill('150');
              await page.locator('#widget_1_transfer_title').fill('pizza');
      
              await page.getByRole('button', { name: 'wykonaj' }).click();
              await page.getByTestId('close-button').click();
              
              await expect(page.locator('#show_messages')).toHaveText('Przelew wykonany! Chuck Demobankowy - 150,00PLN - pizza');
            });
          });
      });
      

      Druga droga (ale łamiąca wiele zasad) to taka gdzie przed testami inicjujemy obiekt page i reużywamy go w testach (nie zalecam ze względu na wiele niedogodności) W playwright.config.ts należy ustawić fullyParallel: false.
      Same testy będą wyglądać tak:

      import { test, expect, Page } from '@playwright/test';
      
      test.describe('test', async () => {
        let page: Page;
        test.beforeAll(async ({ browser }) => {
          page = await browser.newPage();
        });
      
        test('Login to demobank', async () => {
          await page.goto('https://demo-bank.vercel.app/');
          await page.getByTestId('login-input').fill('testerLO');
          await page.getByTestId('password-input').fill('password');
          await page.getByTestId('login-button').click();
        });
      
        test('Preform tranfer', async () => {
          await page.locator('#widget_1_transfer_receiver').selectOption('2');
          await page.locator('#widget_1_transfer_amount').fill('150');
          await page.locator('#widget_1_transfer_title').fill('pizza');
      
          await page.getByRole('button', { name: 'wykonaj' }).click();
          await page.getByTestId('close-button').click();
          
          await expect(page.locator('#show_messages')).toHaveText('Przelew wykonany! Chuck Demobankowy - 150,00PLN - pizza');
        });
      });
      
      
      Przemek Barański Przemek Barański
      1. Dziękuję za komentarz! 🙂

        W takim razie czekam z niecierpliwością na lekcję dotyczącą takiego typu błędu/błędów, właśnie najwięcej napotykam na nie przy testach z wykorzystywaniem wzorca POM.

        Avatar Karolina

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *