<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: SmartHead</title>
    <description>The latest articles on DEV Community by SmartHead (@smarthead).</description>
    <link>https://dev.to/smarthead</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F5922%2F50dc2c3b-6757-4b71-9005-2a7b6cb4cff0.jpg</url>
      <title>DEV Community: SmartHead</title>
      <link>https://dev.to/smarthead</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/smarthead"/>
    <language>en</language>
    <item>
      <title>Efficient Autotesting with Qase: Playwright and GitLab CI Integration</title>
      <dc:creator>Natalia Kudrachinskaya</dc:creator>
      <pubDate>Mon, 15 Jul 2024 10:58:21 +0000</pubDate>
      <link>https://dev.to/smarthead/efficient-autotesting-with-qase-playwright-and-gitlab-ci-integration-201j</link>
      <guid>https://dev.to/smarthead/efficient-autotesting-with-qase-playwright-and-gitlab-ci-integration-201j</guid>
      <description>&lt;p&gt;The approach to maintaining test documentation and the tools chosen for this purpose are crucial parts of the development process that directly affect the product's quality. Keeping test documentation up to date is particularly important. Qase can be an excellent tool for this. Additionally, it helps integrate manual testing with automated testing, and test cases with their execution.&lt;/p&gt;

&lt;p&gt;In this article, we will explore the implementation of Qase integration with Playwright and GitLab CI, as used at SmartHead: from project creation to automated testing reports.&lt;/p&gt;

&lt;h4&gt;
  
  
  Benefits of using Qase, Playwright, and GitLab CI
&lt;/h4&gt;

&lt;p&gt;Qase offers extensive functionality for test management, including test cases, checklists, test runs, and plans, as well as integrations with bug tracking tools. Combined with Playwright and GitLab CI, this provides the following benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Centralized test management:&lt;/strong&gt; A user-friendly interface for maintaining all test cases, plans, and runs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic test creation and synchronization:&lt;/strong&gt; Ensure test cases are up to date and minimize the risk of duplication.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy to integrate and use:&lt;/strong&gt; Playwright simplifies writing and maintaining tests, while GitLab CI automates their execution with every code change.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Detailed reporting:&lt;/strong&gt; Qase provides detailed test execution reports to help you quickly identify and fix bugs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Run tests locally or in CI:&lt;/strong&gt; Ability to run tests locally or in a CI/CD Pipeline with automatic synchronization of each run and test case information in Qase.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Running Pipelines directly from Qase:&lt;/strong&gt; A more integrated and automated testing process. Reports are available in both Qase and GitLab after each run.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Attachment support:&lt;/strong&gt; Ability to attach screenshots, logs, test pass records, and other files to reports for detailed analysis of bugs and issues.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's move on to the implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Set up a project in Qase
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Create a new project in Qase
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Register or log in to your Qase account.&lt;/li&gt;
&lt;li&gt;Create a new project, specifying its name and other necessary data.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frx87zg5j237zzqd4yum2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frx87zg5j237zzqd4yum2.png" alt="empty Qase repository"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Setting up automatic creation of test cases
&lt;/h4&gt;

&lt;p&gt;In the project settings (Settings &amp;gt; Run), enable the option to automatically create new test cases when there are no matches. This will help avoid duplication and keep the test suite up to date.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F67kae7e2sx8nwshldnyq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F67kae7e2sx8nwshldnyq.png" alt="auto create test cases"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When this option is disabled, the test case name from the code will be displayed in the test run, but it will not be added to the repository. When enabled, if the test case is not marked as existing (no ID from Qase is specified), the new test case will be added to the project repository automatically.&lt;/p&gt;

&lt;h4&gt;
  
  
  Create test cases in a project
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Create one or two test cases. We will need them for the next steps.&lt;/li&gt;
&lt;li&gt;Specify the basic parameters such as the name, description, and steps of the test execution.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffa0cv23ft2lnlq52ex92.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffa0cv23ft2lnlq52ex92.png" alt="case elements"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Customize the Qase + Playwright integration
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Install Playwright and playwright-qase-reporter
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to the root directory of the project.&lt;/li&gt;
&lt;li&gt;Following the instructions, install &lt;a href="https://playwright.dev/" rel="noopener noreferrer"&gt;Playwright&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Following the instructions, install &lt;a href="https://www.npmjs.com/package/playwright-qase-reporter" rel="noopener noreferrer"&gt;the reporter for Qase&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Set up the integration in Qase
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Log in to Qase.&lt;/li&gt;
&lt;li&gt;Go to the "Apps" section.&lt;/li&gt;
&lt;li&gt;Locate and select Playwright.&lt;/li&gt;
&lt;li&gt;Set up the integration and save the token you created. You can give it any meaningful name.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4vuuww7ns16sypqi4g7u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4vuuww7ns16sypqi4g7u.png" alt="PW integration"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Set up the configuration in Playwright
&lt;/h4&gt;

&lt;p&gt;Create an &lt;code&gt;.env&lt;/code&gt; file. This file will store our sensitive data for local launch. We will add the copied token from Qase there.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpis17dudq40kiuymqwhm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpis17dudq40kiuymqwhm.png" alt="token in env"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After installing Playwright, playwright.config.ts will appear in the root directory of the project. Open the file and add the following configuration:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 typescript
import { defineConfig, devices } from '@playwright/test';
require('dotenv').config({ path: '.env' }); // Required for using variables from .env

export default defineConfig({
  testDir: './tests', // Your test repository
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  workers: process.env.CI ? 1 : undefined,

  reporter: [
    ['list'],
    ['playwright-qase-reporter',
      {
        testops: {
          project: 'TEST', // Your project code from Qase
          api: {
            token: process.env.QASE_TOKEN, // Token from .env
          },
          run: {
            id: process.env.QASE_RUN_ID,
            complete: true,
          },
          uploadAttachments: true,
        },
      }],
  ],

  use: {
    trace: 'on-first-retry',
  },

  projects: [
    {
      name: 'chromium',
      use: { ...devices['Desktop Chrome'] },
    }
  ],

});


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Don't forget to add the &lt;code&gt;.env&lt;/code&gt; file to .gitignore so you don't accidentally commit the token to the repository.&lt;/p&gt;

&lt;h4&gt;
  
  
  About ID in Qase runs
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;id: process.env.QASE_RUN_ID&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Specifying &lt;code&gt;QASE_RUN_ID&lt;/code&gt; in the configuration is necessary to prevent the creation of different runs in Qase. Without this setting, the automatic run created in Qase and the run that starts the pipeline will be assigned different IDs. By specifying &lt;code&gt;QASE_RUN_ID&lt;/code&gt;, we ensure that the tests from the pipeline are added to the existing run in Qase, if it already exists.&lt;/p&gt;

&lt;h4&gt;
  
  
  Specify the IDs of the cases in the tests
&lt;/h4&gt;

&lt;p&gt;To link tests from Playwright with tests from the Qase repository, we need to specify their IDs in the tests. For convenience, it's better to use names identical to those in Qase. Regardless, the test run will contain the name of the case whose ID you specified.&lt;/p&gt;

&lt;p&gt;Example code of a case test with &lt;code&gt;qase.id()&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 typescript
// test.spec.ts
import { test, expect } from '@playwright/test';
import { qase } from 'playwright-qase-reporter';

test('Display title of Playwright main page', async ({ page }) =&amp;gt; {
  qase.id(1); // ID of the test case in Qase

  // Step #1
  await page.goto('https://playwright.dev/');
  await expect(page).toHaveURL('https://playwright.dev/');
  // Expected result: The page opens

  // Step #2
  const title = await page.getByText('Playwright enables reliable end-to-end testing for modern web apps.');
  await expect(title).toBeVisible();
  // Expected result: The title is displayed
});


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Also for the sake of example, let's write a test where we don't specify &lt;code&gt;qase.id()&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Test that is not in the repository&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Step #1&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://playwright.dev/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toHaveURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://playwright.dev/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="c1"&gt;// Expected result: The page opens&lt;/span&gt;

  &lt;span class="c1"&gt;// Step #2&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Playwright enables reliable end-to-end testing for modern web apps.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeVisible&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// Expected result: The title is displayed&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  Running tests
&lt;/h4&gt;

&lt;p&gt;Run the tests using the command, specifying your path to the tests:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 bash
QASE_MODE=testops npx playwright test tests/test.spec.ts


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  Checking your results in Qase
&lt;/h4&gt;

&lt;p&gt;After successfully running the tests, you will get a link to your run in Qase in the console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fohbj1naznb8y0tfs5ryd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fohbj1naznb8y0tfs5ryd.png" alt="run in Console"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Directly from the console, we can follow the link to view the test run we just executed. You can share this link by making it public or keeping it private. Additionally, you can see detailed information about all the steps of each individual test case, the duration of its execution, and follow the link to view the Pipeline, and so on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fehy0r5fxuv235v64yksv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fehy0r5fxuv235v64yksv.png" alt="automated run in Qase"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The case specified with the ID will pull the existing case from Qase. It will include the steps you have provided and all other information.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu76etuipbjcc1mw7aj75.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu76etuipbjcc1mw7aj75.png" alt="case with the ID"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A case without specifying an ID will be pulled up by default in this state:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqjx035kpdrdvvqm210nv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqjx035kpdrdvvqm210nv.png" alt="case without ID"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The project repository will also include any new test cases that were not previously present. These will be created thanks to the setting we added earlier. If you disable this setting, the tests will still run, but no new test cases will be added to the repository.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmc7lfgqo2h34n3bguyu0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmc7lfgqo2h34n3bguyu0.png" alt="new case in qase repo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A new test case will not be created in subsequent runs. However, it's advisable to include the ID in the code of each test case to prevent confusion.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 3: Integrate Qase with GitLab CI
&lt;/h3&gt;

&lt;p&gt;Create a project on GitLab if it hasn't been created already. Ensure that CI/CD is enabled under Settings -&amp;gt; General -&amp;gt; Visibility, project features, permissions.&lt;/p&gt;
&lt;h4&gt;
  
  
  Customize variables in GitLab
&lt;/h4&gt;

&lt;p&gt;With the &lt;code&gt;.env&lt;/code&gt; file created, we can store configuration data locally. However, to run tests in CI, this data needs to be shared with GitLab. GitLab provides CI/CD Variables for this purpose.&lt;/p&gt;

&lt;p&gt;To add your own variable, you need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to Settings -&amp;gt; CI/CD -&amp;gt; Variables. Here we can save sensitive data similar to the &lt;code&gt;.env&lt;/code&gt; file to use later.&lt;/li&gt;
&lt;li&gt;Click Add variable and in the window that opens, enter QASE_TOKEN in Key and token values in Value.&lt;/li&gt;
&lt;li&gt;Save the data :)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxxmhg8jhd1m0tpcise0w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxxmhg8jhd1m0tpcise0w.png" alt="git variables"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Customize the &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file in a project
&lt;/h4&gt;

&lt;p&gt;There are numerous articles available on CI/CD that can assist you in selecting the optimal approach. Here, I’ll cover only what is needed for integration with Qase.&lt;/p&gt;

&lt;p&gt;Add the &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file to the project root. A minimal configuration example for &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; might look like this:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 yaml
stages:
  - test

test:
  stage: test
  image: mcr.microsoft.com/playwright:v1.42.1-jammy
  script:
    - npm ci
    - npx playwright install
    - QASE_MODE=testops npx playwright test tests/test.spec.ts


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Using the official Docker image from Playwright.&lt;/li&gt;
&lt;li&gt;Installing dependencies.&lt;/li&gt;
&lt;li&gt;Running tests with reports sent to Qase.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After configuring your &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file, remember to push the code to your GitLab repository. Once pushed, the pipeline will execute, and Qase will generate a test run report similar to the one generated previously.&lt;/p&gt;

&lt;h4&gt;
  
  
  Create an automatic test-run in Qase
&lt;/h4&gt;

&lt;p&gt;After all the settings are done, we can start a run in Qase, which will create a Pipeline in GitLab and run the tests.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to Qase.&lt;/li&gt;
&lt;li&gt;Open the Test Runs section and click Start new test run.&lt;/li&gt;
&lt;li&gt;In the test run settings, enter the required data, select GitLab integration, specify the required project, branch, and run the tests.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F835ggnif6zzikv2s5u05.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F835ggnif6zzikv2s5u05.png" alt="start new test run in qase"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A report will also be generated after the run is completed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjtxpp9hnvg1zz5hkvant.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjtxpp9hnvg1zz5hkvant.png" alt="ready test run in qase"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thus, we executed the automated tests in three ways: locally, by committing code changes to the repository, and by initiating an automated test run in Qase. In each scenario, a report was submitted to Qase.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Building software effectively relies on leveraging modern automation and testing tools. Integrating Qase, Playwright, and GitLab CI forms a powerful combination that enhances the development and testing processes.&lt;/p&gt;

&lt;p&gt;Playwright provides rapid and reliable test automation, allowing thorough testing of application functionality across various platforms and browsers, thereby reducing testing durations. GitLab CI ensures that tests are automatically run upon each code update, facilitating early detection and resolution of bugs. Integrating with Qase provides a comprehensive ecosystem within a single platform—from test case creation to automated execution and detailed reporting.&lt;/p&gt;

</description>
      <category>testing</category>
      <category>playwright</category>
      <category>gitlab</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Shifting Frontend to the Server</title>
      <dc:creator>Ramil Aminov</dc:creator>
      <pubDate>Mon, 18 Sep 2023 13:44:39 +0000</pubDate>
      <link>https://dev.to/smarthead/shifting-frontend-to-the-server-3lf9</link>
      <guid>https://dev.to/smarthead/shifting-frontend-to-the-server-3lf9</guid>
      <description>&lt;p&gt;In the past, web applications used to be backend-centric, where HTML pages were generated on the server, and templates were used to add dynamic data.&lt;/p&gt;

&lt;p&gt;As time passed, the demand for interactivity on web pages grew, leading to active advancements in frontend technologies, notably through the adoption of the Single Page Application (SPA) approach. Frameworks evolved to the point where the frontend became a separate application, designed and developed independently by separate teams and hosted separately as well.&lt;/p&gt;

&lt;p&gt;This separation, while having its advantages, leads to several problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The code sent to the browser becomes heavy and grows as the application's functionality increases.&lt;/li&gt;
&lt;li&gt;Much of the logic is moved to the client-side. For example, routing is implemented from scratch and bypasses browser mechanisms.&lt;/li&gt;
&lt;li&gt;Much of the logic is duplicated on the frontend and backend. For example, validation and access control.&lt;/li&gt;
&lt;li&gt;It's necessary to design and develop an API, an additional layer to synchronize frontend and backend, even where the backend only serves the interface.&lt;/li&gt;
&lt;li&gt;The division of specialists into frontend and backend developers in teams creates overhead costs, dilutes the understanding of the final task, and responsibilities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, the principles of how networks and browsers work have not changed: from the user's perspective, web services still appear as complete applications. Frameworks like &lt;a href="https://nextjs.org"&gt;Next.js&lt;/a&gt; are well-suited for such "holistic" development. Their capabilities were significantly limited until recently, but the latest versions of Next.js and React are changing the game.&lt;/p&gt;

&lt;p&gt;React &lt;a href="https://legacy.reactjs.org/blog/2020/12/21/data-fetching-with-react-server-components.html"&gt;introduced server components&lt;/a&gt;, and Next.js implemented them along with a new approach to routing called &lt;a href="https://nextjs.org/docs/app"&gt;App Router&lt;/a&gt;. Essentially, now some React components run on the client, while others run on the server, together forming a single web page. Server components can interact directly with the database, and the API layer becomes optional, replaced by Next.js routing mechanisms. It's now possible to create a full-fledged web application without a backend in the traditional sense. Nevertheless, of course, this does not mean that the backend is not needed at all times. On the contrary, the backend can now focus on its more backend-specific tasks without mixing them with presentation logic.&lt;/p&gt;

&lt;p&gt;By shifting some of the frontend processing and rendering logic to the server-side, we can attain the following benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Accelerated initial page loading times, as the server can pre-render content before delivering it to the client.&lt;/li&gt;
&lt;li&gt;Enhanced search engine optimization (SEO).&lt;/li&gt;
&lt;li&gt;Mitigation of security risks associated with client-side code, as sensitive logic can be safeguarded on the server.&lt;/li&gt;
&lt;li&gt;Increased code reusability between frontend and backend components, streamlining the development process.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Interestingly, for instance, Ruby On Rails, primarily a backend framework, also pushes the boundary of separation, but in a slightly different way. Its authors propose &lt;a href="https://hotwired.dev"&gt;Hotwire&lt;/a&gt; as an alternative to SPA, which involves decomposing and streaming individual parts of HTML.&lt;/p&gt;

&lt;p&gt;Both approaches converge on one point: a significant portion of frontend logic is executed on the server, and we don't lose the benefits of SPA. Thus, the division between the client-side and server-side is not equivalent to the division between frontend and backend. Frontend is a part of the application responsible for interacting with the user and servicing that interaction, including on the server.&lt;/p&gt;

&lt;p&gt;History is progressing in a spiral. More code is executed on the server again, but now we can build client applications of any complexity and beauty with less effort and fewer side effects.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>nextjs</category>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Anchor Links in SPA</title>
      <dc:creator>Nikita Tikhonov</dc:creator>
      <pubDate>Tue, 18 Jul 2023 14:00:00 +0000</pubDate>
      <link>https://dev.to/smarthead/anchor-links-in-spa-38o1</link>
      <guid>https://dev.to/smarthead/anchor-links-in-spa-38o1</guid>
      <description>&lt;p&gt;Single-page applications (SPA) are a popular approach to building modern websites. And it is not just a passing trend: SPAs have a number of advantages over traditional applications.&lt;/p&gt;

&lt;p&gt;The disadvantages of this approach are also known. For example, SPAs may experience search engine optimization (SEO) issues, applications may take a long time to open on the first launch, and can burden users' devices.&lt;/p&gt;

&lt;p&gt;But there are less obvious problems that can arise when developing a SPA. One such problem is broken anchor links.&lt;/p&gt;

&lt;p&gt;Anchor links are used to navigate within a single page. They also allow you to link to a specific section of an external page. For instance, you can share a link to your landing page and immediately scroll the user to the section with information about the company.&lt;/p&gt;

&lt;p&gt;If you try to implement anchor links in a simple SPA, they simply will not work. When following such a link, the browser will display the very beginning of the page and will not scroll to the target section.&lt;/p&gt;

&lt;p&gt;Why is this happening?&lt;/p&gt;

&lt;p&gt;When directly following an anchor link from external resources, the browser scrolls the page to the desired section immediately after the &lt;code&gt;DOMContentLoaded&lt;/code&gt; event occurs. This means that the document has been analyzed, the DOM is ready, and the synchronous and deferred scripts have been loaded and have just started executing. This is how anchor links work in Chrome and Safari, at least. At this moment, it is possible that the required element is simply not present in the document because not all resources have been loaded yet and not all scripts have had a chance to execute.&lt;/p&gt;

&lt;p&gt;And during transitions between pages within a single application (that is, when using, for example, react-router in a single-page application), the browser attempts to navigate to the section by changing the URI before the new page has time to render.&lt;/p&gt;

&lt;p&gt;If you follow the anchor link within the same page, then most likely there will be no difficulties, since in this case all page elements have already been drawn.&lt;/p&gt;

&lt;p&gt;To solve this problem, you can write a script that will scroll the page to the intended element after the DOM has undergone all changes.&lt;/p&gt;

&lt;p&gt;You can also take a ready-made package, for instance, react-router-hash-link for react-router. It fixes a number of problems related to the work of anchors in SPA on React. There are similar implementations for other popular frameworks.&lt;/p&gt;

&lt;p&gt;However, the best option would be to render a full HTML page from the server using server-side rendering (SSR) or a static site generator (SSG). This can be done using Next.js, Gatsby, etc. In this case, when the browser tries to navigate to the desired section, the DOM will already be ready and the target element will be available.&lt;/p&gt;

&lt;p&gt;This way looks more natural. We are not inventing anything new, but using existing mechanisms implemented in browsers long before single-page applications. With the help of modern solutions, we can 'restore' the original working principle of our websites, while maintaining the benefits of the SPA.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>html</category>
    </item>
    <item>
      <title>Decomposition can be excessive</title>
      <dc:creator>Ramil Aminov</dc:creator>
      <pubDate>Fri, 24 Mar 2023 15:37:11 +0000</pubDate>
      <link>https://dev.to/smarthead/decomposition-can-be-excessive-4n8c</link>
      <guid>https://dev.to/smarthead/decomposition-can-be-excessive-4n8c</guid>
      <description>&lt;p&gt;It is commonly believed that decomposition is a good thing. It is indeed useful: it allows us to eliminate uncertainty by breaking down a large, unclear problem into smaller, manageable parts. During the decomposition process, we can better understand the scope of work and even design along the way.&lt;/p&gt;

&lt;p&gt;However, excessive decomposition can be dangerous. It creates the illusion that a feature consists solely of the technical tasks we have broken it down into.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Decomposition incurs overhead costs, not only for creating and working on individual tasks but also for maintaining separate lifecycles and implementing and rolling out each task separately.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The requirement for decomposition can lead to premature design and planning. In order to decompose, design decisions are made without all the necessary information. And when new information appears, it may not be corrected. We may feel compelled to implement the previously decomposed plan.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Decomposition creates an illusion of control. Doing half of the subtasks means you’ve completed half of the feature. Completing all the subtasks means you’ve completed the entire feature. This is not the case. To complete a feature, it is not enough to complete all of its subtasks. The feature is usually more than just the sum of its parts. There is emergent behavior, a value that is given by the combination of the results of the subtasks and which is not present in the simple sum of these results. To complete the feature, this value must also be implemented.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Often, decomposition simply doesn’t make sense. For example, if a feature is simple enough and can be completed in one go.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Feature decomposition is relevant when we break it down by delivery: into pieces that are themselves the end result in terms of product or a use case.&lt;br&gt;
There is no need to decompose a feature into works (for example, “develop a frontend”, “develop a backend”, or “write a migration”). It is better to decompose it into separate “pieces of value”.&lt;/p&gt;

&lt;p&gt;Decomposition should not be a substitute for documentation or a task description. The description should make it clear what should be the result and what should not be forgotten. But not necessarily each of these items should be a separate subtask.&lt;/p&gt;

&lt;p&gt;Another case is when the task is formulated not in terms of value, but in terms of work to be done. In this case, it may be appropriate to decompose it into independent sub-works.&lt;/p&gt;

&lt;p&gt;With the seemingly obvious benefits of decomposition, it can easily become a “fifth wheel”. Like any other management tool, it should be used consciously.&lt;/p&gt;

</description>
      <category>management</category>
      <category>planning</category>
      <category>projects</category>
      <category>task</category>
    </item>
    <item>
      <title>Quality instead of Quality Control</title>
      <dc:creator>Ramil Aminov</dc:creator>
      <pubDate>Thu, 18 Aug 2022 06:46:00 +0000</pubDate>
      <link>https://dev.to/smarthead/quality-instead-of-quality-control-57eo</link>
      <guid>https://dev.to/smarthead/quality-instead-of-quality-control-57eo</guid>
      <description>&lt;p&gt;When discussing quality, complying with a particular set of requirements usually comes to mind. A client, analyst, or someone else sets tasks and people often take those as the requirements. The worst case scenario is that these requirements are taken as non-negotiable, and lead to the wrong results if followed to the letter. This often happens with outsourced development, and it can have a negative impact on the end user’s experience.&lt;/p&gt;

&lt;p&gt;At SmartHead, we believe that there is more to quality than just meeting client demands. It’s not purely complying with requirements, but also the requirements themselves. We do not take only the client’s expectations into consideration, but the end user’s experience too. This means that our concept of quality also includes components such as usability, UI texts, responsiveness, and release frequency.&lt;/p&gt;

&lt;p&gt;High-quality execution means that different needs are satisfied, namely those of the developer, the client, and the end-user.&lt;/p&gt;

&lt;p&gt;How can this be achieved? It’s not easy by any means, but you should adopt a mindset of built-in quality from the start.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quality is about development, not about testing
&lt;/h2&gt;

&lt;p&gt;Quality is often associated with testing. But why?&lt;/p&gt;

&lt;p&gt;Quality is determined by the way in which a product is built, not how it is tested.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkfkq68bww63fu8c40ldq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkfkq68bww63fu8c40ldq.jpg" alt="Responsibility"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The whole team is responsible for quality — especially the developer — who must be sure that the feature under development works correctly. It is wrong to say that a task is done when there is still uncertainty surrounding its completion. You can be confident that everything works well in two different ways: by how you write the code, and by how you organize the whole development process, including testing. However, it is crucial that quality assurance comes down to more than just testing. Moreover, the post-development manual testing stage should not be a bottleneck, and ideally should not be needed at all.&lt;/p&gt;

&lt;p&gt;So, quality engineering should be included in the development process. To say that everything is “done” means that quality is assured.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resilience
&lt;/h2&gt;

&lt;p&gt;In products with long life cycles, changes are inevitable. So alongside its quality at the moment of feature development, “system quality” and its level of resilience are also important.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fljc0eelqvvcbac3tiqcr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fljc0eelqvvcbac3tiqcr.jpg" alt="Resilience"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Making regular changes is completely normal, and products are likely to require much more than just one-off correction. This is only possible if it is certain that changes won’t break anything, and if this is the case, we can say that the system is resilient to change.&lt;/p&gt;

&lt;p&gt;There are issues with resilience or quality if you do not want to touch anything while it is operating, or if the developers are reluctant to discard code they have already written. &lt;/p&gt;

&lt;p&gt;The codebase is not something that we build and hand over. It is our environment that we should make comfortable to work in. It should be easy to add, edit and delete code.&lt;/p&gt;

&lt;h2&gt;
  
  
  No detailed requirements — no problem
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg6u0czprf7vot6lmjrqv.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg6u0czprf7vot6lmjrqv.jpg" alt="Requirements"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If there are no detailed requirements, this does not mean you need to run to the client to ask “where in the UI should this button be?” Nor does it mean that it can go anywhere, however. &lt;/p&gt;

&lt;p&gt;Apart from the incoming requirements (or lack thereof) it’s important to rely on common sense, experience, and taste — and high levels of each of these must be maintained. &lt;/p&gt;

&lt;p&gt;The need to write detailed requirements can put pressure on clients to make important decisions regarding the product despite the fact that they lack either the knowledge or information to do so.&lt;/p&gt;

&lt;p&gt;The absence of detailed requirements is not a problem, but rather an opportunity to do the job as well as possible and adopt a flexible approach towards the project’s scope, taking into consideration the available time and budget. In other words, focusing on the most important elements and ignoring the less significant ones is the best strategy. &lt;/p&gt;

&lt;p&gt;Of course, we should understand what we are doing and why we are doing it, but a detailed description of everything is not necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bugs are inevitable, but not in excess
&lt;/h2&gt;

&lt;p&gt;“Bugs are inevitable” is often said to justify low-quality development. Just because it is impossible to create bugless software does not mean that an excessive amount of bugs is acceptable. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F059dbrdo5pq8p0vx9xom.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F059dbrdo5pq8p0vx9xom.jpg" alt="Bugs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Bugs are OK provided that: they do not prevent you from reaching project goals, they can be fixed quickly, and are not critical for the system’s stability. Severe bugs that break the main use cases occur quite rarely.&lt;/p&gt;

&lt;p&gt;However, if every task is reopened after testing, or if fixing one bug causes three new ones to spring up, it means that there is an issue with quality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not everything is a bug
&lt;/h2&gt;

&lt;p&gt;Bugs can also be viewed from another perspective. Their quantity depends not only on how the code is written, but also on the definition of a bug. Formally, a bug can be found in software of any quality. But not everything needs to be reported because it can just lead to some extra work.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzmpv52b7fiz8qgp4wk9o.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzmpv52b7fiz8qgp4wk9o.jpg" alt="Important bug"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are not suggesting that you ignore bugs, although it is nonetheless important that you understand what requires your attention, and when you can move on. Testers can get bogged down in the details to such an extent that they run out of time to focus on what is actually significant. A lot of time can be lost on checking the layout, which then leaves little opportunity to check the main user scenario. Every task can be returned because of insignificant details, but this can mean that you lose sight of the bigger picture when it comes to quality. When all the tasks are reopened, it is not clear what has been done.&lt;/p&gt;

&lt;p&gt;Moreover, you should not test the developer’s competence. If you spend more time testing their tasks purely because you don’t trust their ability, then bugs aren’t your problem. Instead, it is likely that there is mistrust in the team or the task is too complex for the developer. Ultimately, you should test software, not people — trust them instead.&lt;/p&gt;

&lt;p&gt;In addition, we see little value in testing the design or the written requirements. They themselves, when they are not implemented, bring no value to end-users. You can and should review, discuss, and design them among your team, yet, there is no need to test them formally.&lt;/p&gt;

&lt;p&gt;In a world of endless resources, it would be great to test everything, of course. However, in the here and now, there are simply more important tasks to consider. &lt;/p&gt;

&lt;h2&gt;
  
  
  So what should we test then?
&lt;/h2&gt;

&lt;p&gt;The QA engineer is a product’s “user zero” who knows it well both from outside and inside. They should prioritize the user’s experience rather than checking the developer’s work. They should check what has been done, not what was being done, in other words features, not tasks.&lt;/p&gt;

&lt;p&gt;The QA engineer’s objective is not to find as many bugs as possible, but to ensure that fewer of them make it into the final product. From this point of view, the fewer bugs they find the better.&lt;/p&gt;

&lt;p&gt;The QA engineer is also responsible for accessibility and usability, including copywriting, animations, etc.&lt;/p&gt;

&lt;p&gt;The QA engineer can also improve development quality by contributing their own thought processes. For example, they can help developers to write tests, cover edge cases, and ensure sufficient and reasonable coverage.&lt;/p&gt;

&lt;p&gt;Testing is effective when it aims to bring additional value, and not when it compensates for the drawbacks of development.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Compliance with the requirements that were set initially shouldn’t be the goal. It’s much more important to make a great product.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;User experience should be taken into consideration.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The quality level is set during the development. If time is wasted on compensating poor development with testing, then development, and thus quality, is neglected. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Manual testing should not be a critical need but something that adds to the value.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>codequality</category>
      <category>testing</category>
      <category>qualityassurance</category>
      <category>qa</category>
    </item>
  </channel>
</rss>
