Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mrc-4333 e2e tests #179

Merged
merged 58 commits into from
Mar 18, 2025
Merged

mrc-4333 e2e tests #179

merged 58 commits into from
Mar 18, 2025

Conversation

EmmaLRussell
Copy link
Contributor

@EmmaLRussell EmmaLRussell commented Feb 17, 2025

This branch adds some basic e2e tests, and the framework for running the tests, both locally and against any Packit server. Please see the changes to the top level README for details on how this works.

The index page, packet group page and parts of the packet page are tested.

Some other changes to note:

  • ./scripts/run-e2e-tests-on-server will run generic e2e tests on the specified server with specified auth method (basic or github). If github auth is required, it calls out to a python module, e2e_github_auth.py, which in turn uses pyorderly to manage the github auth, and obtain a packit token. We then need to return this token to the bash script so it can set it as an environment variable which the playwright tests will use. Python scripts cannot set environment variables themselves (outside of the scope of their own copy of the environment) and also cannot return values to the calling script (other than return codes or values written to stdout, on which there is a lot of other chat during the auth process). So here the token is kludgily passed back to the calling script via writing out to a file.
  • app/e2e/auth.setup.ts does authentication according to the required method and credentials provided through environment variables. , or using default basic superuser and password. It is configured as a dependency of the main test projects in playwright.config.ts.

This branch (which includes a couple of markup changes used by the tests) is deployed to packit-dev using the packit-infra PR here. You should be able to run the e2e tests against packit-dev by running:

hatch shell 
pip install pyorderly
./scripts/run-e2e-tests-on-server https://packit-dev.dide.ic.ac.uk/reside-dev/ github

There are separate tickets under the epic for testing:

  • managing roles
  • running packets
  • downloading files and zips
  • other auth paths e.g enter wrong password

We will also need to ensure that any future tests which change the state of the server e.g. running packets or changing user roles are not run on prod servers, but only on localhost or dev. (The tests in this branch are all read-only.).

Codecov is grumbling but there isn't any new untested code.

Copy link

codecov bot commented Feb 17, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 97.16%. Comparing base (2383016) to head (0eb3b65).
Report is 88 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #179      +/-   ##
==========================================
- Coverage   97.29%   97.16%   -0.14%     
==========================================
  Files         150      150              
  Lines        1477     1479       +2     
  Branches      426      428       +2     
==========================================
  Hits         1437     1437              
- Misses         39       41       +2     
  Partials        1        1              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@EmmaLRussell EmmaLRussell marked this pull request as ready for review February 26, 2025 09:37
@EmmaLRussell
Copy link
Contributor Author

Updates following last review

The major changes were abandoning the run-e2e-tests-on-server script and associated python file. Instead, all authentication happens in auth.setup.ts which now:

  • Makes an auth config call to the server to figure out whether basic or github auth is required
  • If basic, requires PACKIT_E2E_BASiC_USER and PACKIT_E2E_BASIC_PASSWORD env vars to be set, and logs in with those
  • If github, checks if GITHUB_ACCESS_TOKEN env var is set. If not, does device flow to get a github token using @octokit/auth-oauth-device. Uses the github token to login to packit.

The other main change was to refactor the division of "local" and generic tests, which were previously matching on file name. Now there are tags for @demoPackets (tests which use the local demo dataset) and @stateMutate (for tests which will change the state of the server by running packets or changing permissions. We don't have any of these yet, but I've added a placeholder test which has this tag). We can include or exclude these tags when running playwright - test runs on dev or prod will probably fail if @demoPackets is included. @stateMutate should never be included when running against prod. I've added a fixture, tagCheckFixture which all tests should use. This checks if we're running tests with unexpected tags given the baseURL, and prints warning messages or throws an error (in the case of @stateMutate tag on non-local or non-dev).

There are now three npm scripts in packit json:

I was going to include functionality to allow user to enter basic username and password interactively if not provided via environment variables, but stdin doesn't seem to be available in the auth.setup script (although I could get it to read input if I made a universal global setup). I presume something in Playwright is tampering with stdin. If it's useful, I can add that, in global setup, or in a separate node script but it's probably not worth it when we can just ask the user to set the variables!

Various other changes from the review comments. Some detailed in replies, and also:

  • Replaced Firefox with Safari, since people insist on using it..
  • renamed workflow file and some of the job names
  • upload test-results, should delete auth.json (but not a big deal if it doesn't)

Testing

The dev and prod scripts script are currently failing because the deployed main branch doesn't include the breadcrumb test id.

To test running non-interactively with github login, run the test:e2e-dev script with env var GITHUB_ACCESS_TOKEN set to your PAT - the tests should run successfully without needing to authenticate interactively: export GITHUB_ACCESS_TOKEN=[your PAT] && npm run test:e2e-dev

You can test triggering the tagCheckFixture by running without tag exclusion:
export PACKIT_E2E_BASE_URL=https://packit-dev.dide.ic.ac.uk/reside-dev/ && npx playwright test or export PACKIT_E2E_BASE_URL=https://packit.dide.ic.ac.uk/reside/ && npx playwright test

Copy link
Contributor

@david-mears-2 david-mears-2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't re-read all of the test files themselves, only the surrounding infrastructure things. My main comment is to suggest a further bit of defence-in-depth to make triply sure we won't be mutating state on prod.

@@ -0,0 +1,93 @@
import { test as setup, expect, Page } from "@playwright/test";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this import test and expect from tagCheckFixture instead?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am uncomfortable relying on developers to remember to check that they are importing 'test' from the correct place. Especially since IDEs often write imports for you. We could do something like the following, in a global setup script akin to auth.setup.js that is listed as a dependency for all test projects in playwright config:

function checkImports(filePath) {
  const content = fs.readFileSync(filePath, 'utf-8');
  const importRegex = /import\s+{[^}]*\btest\b[^}]*}\s+from\s+".\/tagCheckFixture";/;
  if (!importRegex.test(content)) {
    throw new Error(`Test file ${filePath} does not import 'test' from 'tagCheckFixture'.`);
  }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't think it really matters for the auth setup test but yeah, for the purposes of setting a good example let's do that!

checkImports is a great idea. Actually, I'd be inclined to do that in auth.setup itself (possibly with a rename to reflect more generic concerns) as further defence, since people could still forget to include checkImports.setup.ts as a dependency, but their tests aren't going to get anywhere if they don't include the dep that does auth...

@EmmaLRussell
Copy link
Contributor Author

EmmaLRussell commented Mar 17, 2025

I've implemented the suggested checkImports method in a globalSetup script rather than within the auth setup (it runs first before any other project). It uses a generic glob search for test files under the test root dir, then loads all the file contents and checks for the suggested regex match of loading test from tagCheckFixture. Test by changing one of the test files to import test from @playwright/test

The fs glob search is new and experimental in node 22 - I've updated the node version in CI.

I've also updated the dev and prod urls now they're on proper subdomains, and also made sure the BASIC_AUTH variable is set in the dev-start script (it caused an error if running in github mode).

Copy link
Member

@plietar plietar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, just some minor bits

await expect(link).toHaveText(packetId);
const expectedHref = getInstanceRelativePath(baseURL, `parameters/${packetId}`);
await expect(await link.getAttribute("href")).toBe(expectedHref);
// We expect servers we're testing on to have either GB or US locale.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// We expect servers we're testing on to have either GB or US locale.
// We expect browsers we're testing on to have either GB or US locale.

No? I'd be surprised if we did any date rendering server side. The JS should pick up the browser defaults.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually you can set the locale in the playwright config, that should make this more reliable..

};

// Get a relative path which includes the packit instance, if any
export const getInstanceRelativePath = (baseURL: string, path: string) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So as of last Friday we're now running all instances at the root path, meaning we could actually remove this function.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might just leave it in for now just in case we run any old style multi-tenancies again!

export const TAG_DEMO_PACKETS = "@demoPackets";

const isLocal = (baseURL: string) => baseURL.startsWith("http://localhost");
const isDev = (baseURL: string) => baseURL.startsWith("https://packit-dev.dide.ic.ac.uk");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is broken now that the URL has changed. You would need to parse the URL, extract the domain name and check if that part ends in packit-dev.dide.ic.ac.uk

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something like

Suggested change
const isDev = (baseURL: string) => baseURL.startsWith("https://packit-dev.dide.ic.ac.uk");
const isDev = (baseURL: string) => new URL(baseURL).hostname.endsWith("https://packit-dev.dide.ic.ac.uk");

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, have added that.

Copy link
Contributor

@david-mears-2 david-mears-2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you!

Perhaps the version of "@types/node" (package.json) wants to be kept in sync with the node version - it's still on 16.

Copy link
Contributor

@david-mears-2 david-mears-2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, just noticed app/Dockerfile has node 18 still as well. Also line 6 of app/README.md cites Node 18.

@EmmaLRussell
Copy link
Contributor Author

Sorry, just noticed app/Dockerfile has node 18 still as well. Also line 6 of app/README.md cites Node 18.

😱 So many node versions! Great spot!

@EmmaLRussell EmmaLRussell merged commit 9937f93 into main Mar 18, 2025
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants