This lab focuses on configuring eslint to identify and fix lint issues, updating package dependencies, and optionally creating a Playwright UI Test project.
- The prerequisites steps must be completed, see Labs Prerequisites
- 20 minutes, times may vary with optional labs.
Important
Ensure error-free results by meticulously following each step of the lab instructions.
- This lab focuses on configuring ESLint for identifying and resolving lint issues, updating package dependencies, and optionally setting up a Playwright UI testing project
- Step 1: Eslint configuration and fix lint issues.
- Step 2: Upgrade to Business Class - Update Package Dependencies.
- Step 3: PlayWright UI Test project using /new command.
-
In this lab, we will configure eslint and fix lint issues in the WrightBrothersFrontend project. eslint is a tool that helps you find and fix problems in your JavaScript code. It is similar to Roslyn Analyzer in the .NET.
-
Close any files that are opened.
-
From the
WrightBrothersFrontend/directory, run the following command to see the current lint issuesnpm run lint
-
No lint issues should be present.
-
Open the
WrightBrothersFrontend/.eslintrc.cjsfile. -
Notice the lint rules are the recommended rules from
eslintandreact. We want to add more lint rules to harden the project. -
Open GitHub Copilot Chat, then click
+to clear prompt history. -
Select all the contents of the
.eslintrc.cjsfile. -
Type the following in the chat window:
What linting rules can I add to #selection to harden my project more and tell me why for each? Only give me rules that are not already part of the recommended rules. -
Press
Enterto submit the question -
GitHub Copilot suggested the following rules:
module.exports = {
// existing configuration...
rules: {
// existing rules...
"no-console": "error",
"eqeqeq": "error",
"curly": "error",
"no-eval": "error",
"no-unused-vars": "error",
},
};Note
Note that GitHub Copilot now suggested rules and also provided a reason to why implement a specific rule. This is a great way to learn more about the rules and why they are important.
-
In the Copilot Chat window, click
Insert at CursororApply in Editor. -
When using
Apply in Editor, be sure to clickAccept Changesfor each change.
Click for Solution
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react-hooks/recommended",
],
ignorePatterns: ["dist", ".eslintrc.cjs"],
parser: "@typescript-eslint/parser",
plugins: ["react-refresh"],
rules: {
"react-refresh/only-export-components": [
"warn",
{ allowConstantExport: true },
],
"@typescript-eslint/no-explicit-any": "off",
"no-console": "warn",
"eqeqeq": ["error", "always"],
"curly": ["error", "all"],
"no-unused-vars": ["error", { "args": "none" }],
"no-var": "error",
"prefer-const": "error",
"react/jsx-uses-react": "error",
"react/react-in-jsx-scope": "error",
"react/prop-types": "error",
},
};-
Run
npm run lintto scan for lint issues with the new rulesnpm run lint
-
You should now see many lint issues related to the new rules
/Copilot-Bootcamp/WrightBrothersFrontend/src/pages/PlaneDetail.tsx
77:16 error Expected '===' and instead saw '==' eqeqeq
87:5 error Expected { after 'if' condition curly
/Copilot-Bootcamp/WrightBrothersFrontend/src/services/PlaneService.ts
12:5 error Unexpected console statement no-console-
Ask Copilot to fix the lint issues
-
Go to the lint issues in
WrightBrothersFrontend/src/pages/PlaneDetail.tsx. -
Find the following code snippet that contains the
eqeqeqlint issue:
if (!planeDetails)
return <div>Plane not found</div>;-
Right-clickon the first lint issue and select/Fixto fix using Copilot from the context menu.
-
GitHub Copilot will now open a Inline Editor window with the suggested fix. Review the fix and click
Acceptto apply the fix. -
Repeat for the other lint issues. You can also try
Explain using Copilotto understand why the rule is important.
-
In this lab, we will create visual component tests for the PlaneList component in the WrightBrothersFrontend project. Visual component testing is a new way of testing the interaction and appearance of components in isolation.
-
Open GitHub Copilot Chat, then click
+to clear prompt history. -
For these tests we are using Playwright, a tool for automating browsers. Playwright is similar to Selenium but with a more modern API and better performance.
-
Let's first run the existing tests in the project. Run
npm run test-ct(component test) to see the existing tests pass.cd WrightBrothersFrontend/npm run test-ct
-
You should see that all tests pass
Running 2 tests using 2 workers 2 passed (4.8s)
Note
If you encounter any of the following errors, follow the provided steps to resolve them:
-
Error:
browserType.launch: Executable doesn't exist.- This error indicates a problem with your Playwright installation. Please check your installation and fix any issues before proceeding.
-
Error:
Looks like Playwright Test or Playwright was just installed or updated.- This error usually occurs after a new installation or update of Playwright. If you see this, try running the command below to install the necessary Playwright dependencies:
npx playwright install
- Try again, run the existing tests in the project. Run
npm run test-ct(component test) to see the existing tests pass.
npm run test-ct
-
We are going to add tests to the already existing
PlaneList.spec.tsxfile in thesrc/componentsfolder. -
Open
GitHub Copilot Edits, then click+forNew Edit Session. -
Add the following files to the
Working Setnear the bottom of Copilot Edits window. -
Click the
+ Add filesbutton, then select these:PlaneList.tsxPlaneList.spec.tsx
Note
You can multi-select these files from the file explorer by holding the Ctrl down and Left-Clicking on each file. Then simply drag-n-drop them into Copilot Edits working set window.
-
Copy/Paste the following in the Copilot Edits Chat window:
Create the remaining tests for #file:PlaneList.tsx based on test file #file:PlaneList.spec.tsx
Note
If the result is incomplete or doesn't work, simply retry the prompt.
-
Press
Enterto submit the prompt. -
You can choose to
AcceptorDiscardthe changes in the file editor or theWorking Setwindow. -
Copilot used
PlaneList.tsxto match the style of the form to the existing<PlaneList />component. -
Then new tests were added to
PlaneList.spec.tsx. -
Click
Acceptto save the changes, then clickDonein theCopilot Editswindow to complete this task. -
If Copilot didn't suggest the code above, then update the code manually as follows:
Click for Solution
import { test, expect } from '@playwright/experimental-ct-react';
import PlaneList from './PlaneList';
import type { HooksConfig } from '../../playwright';
test('should navigate when clicking on a plane', async ({ page, mount }) => {
const planes = [
{ id: 1, name: "Wright Flyer" },
{ id: 2, name: "Wright Model A" },
{ id: 3, name: "Wright Model B" },
];
const component = await mount<HooksConfig>(<PlaneList planes={planes} />, {
hooksConfig: { routing: true },
});
await component.locator('li').nth(0).click();
await expect(page).toHaveURL('/planes/1', { timeout: 5000 });
});
test('should navigate when clicking on the second plane', async ({ page, mount }) => {
const planes = [
{ id: 1, name: "Wright Flyer" },
{ id: 2, name: "Wright Model A" },
{ id: 3, name: "Wright Model B" },
];
const component = await mount<HooksConfig>(<PlaneList planes={planes} />, {
hooksConfig: { routing: true },
});
await component.locator('li').nth(1).click();
await expect(page).toHaveURL('/planes/2', { timeout: 5000 });
});
test('should navigate when clicking on the third plane', async ({ page, mount }) => {
const planes = [
{ id: 1, name: "Wright Flyer" },
{ id: 2, name: "Wright Model A" },
{ id: 3, name: "Wright Model B" },
];
const component = await mount<HooksConfig>(<PlaneList planes={planes} />, {
hooksConfig: { routing: true },
});
await component.locator('li').nth(2).click();
await expect(page).toHaveURL('/planes/3', { timeout: 5000 });
});
test('should add flying class to image when clicking on a plane', async ({ mount }) => {
const planes = [
{ id: 1, name: "Wright Flyer" },
{ id: 2, name: "Wright Model A" },
{ id: 3, name: "Wright Model B" },
];
const component = await mount<HooksConfig>(<PlaneList planes={planes} />, {
hooksConfig: { routing: true },
});
const firstPlane = component.locator('li').nth(0);
await firstPlane.click();
const imgElement = firstPlane.locator('img');
await expect(imgElement).toHaveClass(/flying/);
});-
The created tests do not always compile. GitHub Copilot got you 90% of the way there, but you may need to make some adjustments to the code to make it work. You can also ask Copilot for help with this. Try
Fix using CopilotorExplain using Copilotto get help with the code. -
Now run the tests again but then with the UI open
npm run test-ct:open
-
In a DevContainer or CodeSpace you might see the following error:
'╔════════════════════════════════════════════════════════════════════════════════════════════════╗\n' + '║ Looks like you launched a headed browser without having a XServer running. ║\n' + "║ Set either 'headless: true' or use 'xvfb-run <your-playwright-app>' before running Playwright. ║\n" + '║ ║\n' + '║ <3 Playwright Team ║\n' + '╚════════════════════════════════════════════════════════════════════════════════════════════════╝'
-
Run the following command to run the tests without the UI
npm run test-ct
-
You should see the tests in the PlayWright UI. You can press the play button in the UI to run the tests.
-
You should see that all tests pass
Running 2 tests using 2 workers 2 passed (4.8s)
-
Not all tests will pass. You can now debug the tests in the PlayWright UI and fine-tune the tests to make them pass.
-
Now stop the Frontend and API by pressing
Ctrl + Cin the terminal.
-
In this lab, we will create a new Playwright UI Test project using the /new command in GitHub Copilot.
-
If you have not already done the lab for creating a form with GitHub Copilot. Copy/paste the following code inside
/WrightBrothersFrontend/src/pages/NewPlane.tsx
Click for Solution
import React from 'react'; import { Formik, Field, Form, ErrorMessage } from 'formik'; import * as Yup from 'yup'; import { useNavigate } from 'react-router-dom'; import axios from 'axios'; import PageContent from '../components/PageContent'; const PlaneSchema = Yup.object().shape({ id: Yup.number().required('Required'), name: Yup.string().required('Required'), year: Yup.number().required('Required'), description: Yup.string().required('Required'), rangeInKm: Yup.number().required('Required'), }); const NewPlane = () => { const navigate = useNavigate(); return ( <PageContent> <h1>New plane</h1> <Formik initialValues={{ id: '', name: '', year: '', description: '', rangeInKm: '', }} validationSchema={PlaneSchema} onSubmit={(values, { setSubmitting }) => { axios.post('http://localhost:1903/planes', values) .then(() => { setSubmitting(false); navigate('/'); }); }} > {({ isSubmitting }) => ( <Form className="space-y-4"> <div> <label htmlFor="id" className="block text-sm font-medium text-gray-700">ID</label> <Field id="id" type="number" name="id" className="mt-1 block w-full" /> <ErrorMessage name="id" component="div" /> </div> <div> <label htmlFor="name" className="block text-sm font-medium text-gray-700">Name</label> <Field id="name" type="text" name="name" className="mt-1 block w-full" /> <ErrorMessage name="name" component="div" /> </div> <div> <label htmlFor="year" className="block text-sm font-medium text-gray-700">Year</label> <Field id="year" type="number" name="year" className="mt-1 block w-full" /> <ErrorMessage name="year" component="div" /> </div> <div> <label htmlFor="description" className="block text-sm font-medium text-gray-700">Description</label> <Field id="description" type="text" name="description" className="mt-1 block w-full" /> <ErrorMessage name="description" component="div" /> </div> <div> <label htmlFor="rangeInKm" className="block text-sm font-medium text-gray-700">Range in Km</label> <Field id="rangeInKm" type="number" name="rangeInKm" className="mt-1 block w-full" /> <ErrorMessage name="rangeInKm" component="div" /> </div> <button type="submit" disabled={isSubmitting} className="mt-4 inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"> Submit </button> </Form> )} </Formik> </PageContent> ); }; export default NewPlane;
-
First, Make sure that the Frontend is running. This is because the Playwright UI Test project will interact with the Frontend.
cd WrightBrothersFrontend/npm run frontend-and-backend
npm run test-ct
-
If you haven't done so already, we need to make port
1903public instead of private to allow access to list of planes.-
Click the
PORTSbutton (near bottom center). -
With your cursor over port 1903,
Right-Click, selectPort Visability, then clickPublic.[!NOTE] Making port 1903 public is necessary to allow external access to the service running on that port. In this context, the service provides a list of planes, and making the port public ensures that users can access this information from outside the local development environment (a Codespace).
-
-
-
Open the browser and navigate to your URL
/new-plane.- i.e.
https://super-duper-space-robot-4v6rvqwggx25xq7-5173.app.github.dev/new-plane
- i.e.
-
Open GitHub Copilot Chat, then click
+to clear prompt history. -
Type the following in the chat window:
@workspace /new Playwright UI Tests ## Purpose I want to create a new Playwright UI Test project to test the form at "/new-plane". ## Test - Navigate to "/new-plane" and fill out the form through the "name" attribute: id, name, year, description, rangeInKm ## Technical Requirements - UI mode - localhost:5173 is the base URL - Typescript - Include package.json - Use @playwright/test library ## Folder Structure - Parent Folder: WrightBrothersFrontend/ Make a complete solution.
-
Press
Enterto submit the question -
GitHub Copilot will now scaffold a new Playwright UI Test project
-
Click
Create Workspaceto create the new Playwright UI Test project.
-
Select the
WrightBrothersFrontend/as theParent Folderto create the new project. -
GitHub Copilot will now open the new project in a new window.
-
Now stop the Frontend and API by pressing
Ctrl + Cin the terminal. -
Open the terminal and navigate to the
WrightBrothersFrontend/<new folder created>directory.-
i.e.
cd WrightBrothersFrontend/playwright-ui-testingcd WrightBrothersFrontend/playwright-ui-testing
npm install
-
-
Now, run the tests
npm run test -
The tests fail, because most likely playwright needs to install additional dependencies, run the following command to install the dependencies
npx playwright install
-
Now, run the tests again, but now with the UI open to see the tests run in the Playwright UI
npm run test --ui -
You should see the tests pass in the UI or in the terminal
Running 1 test using 1 worker ✓ 1. should navigate to /new-plane and fill out the form (1.5s) -
GitHub Copilot just created a new Playwright UI Test project for you with successful tests. You can now use this project to create more tests for the WrightBrothersFrontend project.
