Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

Run e2e tests inside a docker container #1057

Merged
merged 43 commits into from
Mar 18, 2022
Merged

Run e2e tests inside a docker container #1057

merged 43 commits into from
Mar 18, 2022

Conversation

sarayourfriend
Copy link
Contributor

@sarayourfriend sarayourfriend commented Mar 4, 2022

Fixes

Related to and blocks #1017 by @sarayourfriend

I originally started working on this directly in the same PR to address #1017 but decided to split this work out and apply it to the existing e2e tests to minimize the scope of the visual regression testing PR.

Description

Note about the line count for this PR!

The vast majority of those changes are in the updated tapes due to the sudden introduction of Brotli compression halfway through developing this. The main places to focus reviews on are the following:

  1. playwright.config.ts
  2. docker-compose.playwright.ts
  3. proxy.js

Rationale

In order for visual regression tests to run in docker (to alleviate cross-platform rendering differences causing false-positives in the snapshot tests) we need to be able to have the full playwright stack working in docker due to networking complications.

Because our app is SSR and client side rendered, there are two contexts in which API requests are made:

  1. In the SSR application
  2. In the docker contained headless browser that is being controlled by playwright

If we just run playwright inside of docker, then we run into an issue where our API url has to be different for the client and the server, because the server will be on the host network and can use localhost, whereas the client will be in the docker network and will need to use something like host.docker.internal. This complicates the code and also makes debugging difficult.

Solution

To fix this, we run everything inside a single Playwright docker container so that they all share the same network and (crucially) can communicate over plain old localhost. Without being able to use localhost (i.e., relying on docker-compose networking) we can lots of weird SSL errors with the browser automatically redirecting requests to places like http://web or http://api to https. These fail because we don't have SSL set up locally.

Instead, I discovered that Playwright actually has built into it the ability to run and wait for a server to start! This means we can run the talkback proxy and the Nuxt server all inside the same container as Playwright, still get the benefits of the Playwright container's browser, all without the hassle of setting up local SSL for everyone trying to run the e2e tests locally.

The only snag here is that writing new tapes from talkback needs to have some permissions juggling fixed for Linux. Apparently this is a non-issue on macOS and Windows because the volumes are shared in a different way, but on Linux files written by docker containers into the host will all have root permissions. To fix this, we can just run chmod on them after updating the tapes. To prevent having to run a sudo script inside our package.json, I chose to just use the node:alpine image to run chmod as the image will already be present on your machine if you run the e2e tests because it's used as the base image for the running Nuxt app. I think we could also use the Playwright image but we need to interpolate the Playwright version to avoid downloading extraneous versions and node:alpine doens't have that problem.

I had to use npm-run-all because pre/post scripts in npm do not run if the main script fails, so if you try to update tapes and the tests don't pass, then the permissions fix won't run. npm-run-all with the --continue-on-error flag set will run all the scripts in sequence even if one of them fails while also still producing a non-zero exit code if any of the scripts produce non-zero exit codes.

Meta commentary about the PR

There are a few long caveat laden comments that needed to be added to explain everything that was going on, specifically with a few edge cases here and there. If when reviewing you find any other places that need clarification, don't hesitate to ask me to add more comments. Given the complexity and depth of this change I think more explanatory comments are best, for our own sanity's sake down the line when we're trying to understand how this all works again.

I actually think that the solution I landed on is ultimately simpler than the solutions I explored along the way. For example, this still uses docker-compose to run the Playwright container, but that's mostly just so that we don't have to stuff all the options into a long docker run line.

Related fixes

Because I was debugging all sorts of broken https requests, I was carefully inspecting the tapes and requests being made by the frontend. I discovered that the thumbnail routes were not being proxied. This PR also fixes that (hence the enormous number of new tapes being added).

Halfway through working on this I ran into an issue where some responses that were being recorded by talkback when updating/creating new tapes were compressed. Talkback, for some reason, doesn't decompress them for you. That's fine because zlib is built into Node anyway and we can easily decompress and recompress responses. I don't know why we didn't run into this previously but as I mentioned in the comment in proxy.js I think it's actually good that we're dealing with it because it more closely mirrors the situation in production.

It does, however, raise the question of why some responses aren't Brotli compressed and others are.

In light of @obulat's existing PR to fix up some of the tape generation logic in #1045 we can hold off on merging this PR until her changes are in. I think it'll be easier to merge in her changes to this PR than the other way around. @obulat feel free to correct me if you think the other way will be easier! I'm not sure if your PR is running into the same Brotli compression issue I ran into with this one, but if so then the other way around (merge this first then rebase the other branch) might be easier. I will leave that up to you though, Olga.

Testing Instructions

Checkout this PR and run pnpm test:e2e and pnpm test:e2e:update-tapes and ensure that they work (i.e., that talkback responses are being used/created, file permissions are set correctly, etc). Also try pnpm test:e2e:debug with and without a local Nuxt server running. Both should work. pnpm generate-playwright-tests is unaffected, but I renamed it in anticipation of visual-regression being added and the generate script no longer being specific to just "e2e" tests.

Checklist

  • My pull request has a descriptive title (not a vague title like Update index.md).
  • My pull request targets the default branch of the repository (main) or a parent feature branch.
  • My commit messages follow best practices.
  • My code follows the established code style of the repository.
  • I added or updated tests for the changes I made (if applicable).
  • I added or updated documentation (if applicable).
  • I tried running the project locally and verified that there are no visible errors.

Developer Certificate of Origin

Developer Certificate of Origin
Developer Certificate of Origin
Version 1.1

Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
1 Letterman Drive
Suite D4700
San Francisco, CA, 94129

Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.


Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I
    have the right to submit it under the open source license
    indicated in the file; or

(b) The contribution is based upon previous work that, to the best
    of my knowledge, is covered under an appropriate open source
    license and I have the right under that license to submit that
    work with modifications, whether created in whole or in part
    by me, under the same open source license (unless I am
    permitted to submit under a different license), as indicated
    in the file; or

(c) The contribution was provided directly to me by some other
    person who certified (a), (b) or (c) and I have not modified
    it.

(d) I understand and agree that this project and the contribution
    are public and that a record of the contribution (including all
    personal information I submit with it, including my sign-off) is
    maintained indefinitely and may be redistributed consistent with
    this project or the open source license(s) involved.

@sarayourfriend sarayourfriend added 🟧 priority: high Stalls work on the project or its dependents 🌟 goal: addition Addition of new feature 🤖 aspect: dx Concerns developers' experience with the codebase 🐳 tech: docker Requires familiarity with Docker 💲 tech: bash Requires familiarity with Bash labels Mar 4, 2022
@sarayourfriend sarayourfriend requested a review from a team as a code owner March 4, 2022 17:38
@sarayourfriend sarayourfriend requested review from krysal and obulat March 4, 2022 17:38
@todo(sarayourfriend): Find a way to de-duplicate the
docker-compose invocation. Perhaps a separate bash script
in `bin`?
@sarayourfriend
Copy link
Contributor Author

sarayourfriend commented Mar 4, 2022

I've gotten very far with this. I think the final issue that remains is to fix the various SSL errors that happen. You can see these by modifying the playwright.config.js to include use: { trace: 'on' }, extracting the trace.zip created in test-results and opening the trace.trace file. Search for https and you'll find several requests to both https://api:3000 and https://web:8443. I'm not sure what is causing this to be honest but I ran into it with the visual regression PR I was working on as well.

As I see it there are really two solutions:

  1. Either somehow force http to be used across the board (I'm assuming this is the easiest solution)
  2. Allow SSL to be used between containers, potentially by using a reverse proxy like caddy between them (probably a little harder BUT would be more in line with production so could be more desirable if the effort is low)

I plan to tackle these in reverse order. If it's possible to get SSL working between the containers without too much effort, then I think that is preferable because as I mentioned it is closer to production anyway. I suspect the first solution will also require some hacking/brute force solution that would be best to avoid.

const banner = await page.locator(
'.span:has-text("Help us get to 100 percent")'
)
const banner = page.locator('.span:has-text("Help us get to 100 percent")')
Copy link
Contributor Author

Choose a reason for hiding this comment

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

page.locator doesn't return a Promise. Completely unrelated to this PR but it was bugging me while I was debugging this particular test 😅

@zackkrida zackkrida requested review from zackkrida and removed request for zackkrida March 11, 2022 14:12
@sarayourfriend sarayourfriend changed the title Run e2e tests inside a docker-compose stack Run e2e tests inside a docker container Mar 14, 2022
/**
* Default environment variables are set on this key. Defaults are fallbacks to existing env vars.
* All boolean values should be designed to be false by default.
*/
export const env = {
apiUrl: process.env.API_URL ?? 'https://api.openverse.engineering/',
apiUrl: apiUrl.endsWith('/') ? apiUrl : `${apiUrl}/`,
Copy link
Member

Choose a reason for hiding this comment

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

👍

@zackkrida
Copy link
Member

Getting Brotli related errors in my attempts to test this:

Full terminal output
front on  try/e2e-docker +/- [$] via  v16.13.0
❯ pnpm test:e2e

> [email protected] pretest:e2e /Users/zackkrida/Code/openverse/front
> pnpm install

Lockfile is up-to-date, resolution step is skipped
Already up-to-date

> [email protected] prepare /Users/zackkrida/Code/openverse/front
> husky install

husky - Git hooks installed

> [email protected] test:e2e /Users/zackkrida/Code/openverse/front
> cross-env PLAYWRIGHT_VERSION=1.17.1 TEST_TYPE=e2e docker-compose -f docker-compose.playwright.yml up --abort-on-container-exit --exit-code-from playwright

WARN[0000] Found orphan containers ([front_web_1]) for this project. If you removed or renamed this service in your compose file, you can run this command with the --remove-orphans flag to clean it up.
[+] Running 1/0
 ⠿ Container front-playwright-1  Created                                                                                                                                                                                                                                                                                 0.0s
Attaching to front-playwright-1
front-playwright-1  |
front-playwright-1  | > [email protected] test:e2e:local /app
front-playwright-1  | > playwright test -c test/e2e
front-playwright-1  |
front-playwright-1  | [WebServer] 2022-03-14T14:37:43.272Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-106.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:43.280Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-107.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:43.397Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-114.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:43.471Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-117.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:43.595Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-121.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:43.708Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-125.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:43.962Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-13.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:44.673Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-15.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:45.234Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-175.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:45.253Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-179.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:45.297Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-180.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:45.311Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-181.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:45.413Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-185.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:45.428Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-186.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:45.439Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-187.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:45.623Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-190.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:45.723Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-21.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:45.759Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-24.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:46.021Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-30.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:46.470Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-42.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:47.053Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-58.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:47.056Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-59.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:47.074Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-60.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:47.089Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-61.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:47.340Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-68.json5 Unsupported content-encoding br
front-playwright-1  | [WebServer] 2022-03-14T14:37:47.370Z [Openverse e2e proxy] [ERROR] Error reading tape test/tapes/response-70.json5 Unsupported content-encoding br

@sarayourfriend
Copy link
Contributor Author

@zackkrida that's a talkback error: https://github.com/sarayourfriend/talkback/blob/7226f9c24ad78957575750cc39a3b17787270602/src/utils/content-encoding.ts#L39

Just need to update to the most recent version of talkback since my PR to add Brotli support was merged upstream: https://github.com/ijpiantanida/talkback/releases/tag/v3.0.1

@sarayourfriend
Copy link
Contributor Author

@zackkrida Ready for re-review.

@sarayourfriend
Copy link
Contributor Author

@zackkrida I'm going to push another commit to solve an issue with duplicate tapes that @obulat pointed out to me. Should be pushing it within the next hour or so.

@obulat
Copy link
Contributor

obulat commented Mar 16, 2022

Running the tests with pnpm test:e2e works well, but only if I increase the timeout in playwright.config.ts. Updating tapes works well, too. But running in debug mode causes the container to fail. This is what I see in the Docker log:

undefined
 ERR_PNPM_RECURSIVE_EXEC_FIRST_FAIL  not found: test::local

@sarayourfriend
Copy link
Contributor Author

@obulat What command did you use to run the debug? pnpm test:e2e:debug? It looks like somehow the tests were run without a TEST_TYPE for one of the docker-based approaches... 🤔

@sarayourfriend
Copy link
Contributor Author

but only if I increase the timeout in playwright.config.ts

I'll increase the timeout to five minutes I think.

@sarayourfriend
Copy link
Contributor Author

@obulat I tried running pnpm test:e2e:debug locally and it worked fine for me 😕 Unfortunately we can't reuse the docker approach for debugging tests because docker would need to connect to a running Xorg server to be able to display the headed browsers.... and configuring that just for one OS is hard enough, making it cross platform to macOS, Linux, and Windows (even with WSL) would require a lot of work. Maybe one day we can tackle that but for now test:e2e:debug's approach is the only way 😞

Copy link
Contributor

@obulat obulat left a comment

Choose a reason for hiding this comment

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

Well, debugging works locally, and e2e tests run well in docker. This is such a great improvement, and it's great that you split this part of the change into a separate smaller PR:)

@sarayourfriend
Copy link
Contributor Author

@zackkrida can you re-review today if you have time? I'd like to merge this to avoid any more merge conflicts. Thanks!

@sarayourfriend
Copy link
Contributor Author

@krysal Would you be able to review this when you have a chance?

Copy link
Member

@zackkrida zackkrida left a comment

Choose a reason for hiding this comment

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

LGTM. This is working flawlessly for me now. My only nit is that after running pnpm test:e2e, this is the only output for 2-3 minutes:

Starting front_playwright_1 ... done
Attaching to front_playwright_1
playwright_1  |
playwright_1  | > [email protected] test:e2e:local /app
playwright_1  | > playwright test -c test/e2e
playwright_1  |
playwright_1  |

If we could log a message or something right away that indicates that a bunch of background work is happening, that might reassure users while this is loading. I worry about folks with slower machines than my m1 macbook pro. I left an inline comment with a suggestion on how to do this.

- .:/app
user: ${PW_USER:-pwuser}
working_dir: /app
command: pnpm test:${TEST_TYPE}:local
Copy link
Member

Choose a reason for hiding this comment

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

Could do something here to log a message like so:

   command: >
      sh -c "echo Some type of message here
             pnpm test:${TEST_TYPE}:local"

@sarayourfriend sarayourfriend merged commit ba9a8d9 into main Mar 18, 2022
@sarayourfriend sarayourfriend deleted the try/e2e-docker branch March 18, 2022 11:34
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
🤖 aspect: dx Concerns developers' experience with the codebase 🌟 goal: addition Addition of new feature 🟧 priority: high Stalls work on the project or its dependents 💲 tech: bash Requires familiarity with Bash 🐳 tech: docker Requires familiarity with Docker
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants