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

[NOT READY] Playwright #4752

Draft
wants to merge 51 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
e5dd868
Playwright install
macobo Oct 24, 2024
0b14055
Fixed seed for seeds.exs support
macobo Oct 24, 2024
2ee0a20
Simple login test
macobo Oct 24, 2024
c0dbd81
Simple sites page test
macobo Oct 24, 2024
35875e3
Throw if any uncaught javascript errors
macobo Oct 24, 2024
9497f35
Test keyboard shortcuts
macobo Oct 24, 2024
95d2d67
Add more testids
macobo Oct 25, 2024
d3a819c
Update viewport size to fit the whole page
macobo Oct 25, 2024
c8ad096
Add some more simple tests
macobo Oct 25, 2024
776d804
Write tests opening each modal
macobo Oct 26, 2024
63fba85
Seed with Properties configured
macobo Oct 26, 2024
f0e6b54
Test comparisons
macobo Oct 26, 2024
37da79d
fix alignment issues
macobo Oct 28, 2024
17e4b98
Update playwright reporter
macobo Oct 28, 2024
076f449
README.md for frontend tests
macobo Oct 29, 2024
8f54fcc
Comparison mode open tooltips tests
macobo Oct 29, 2024
36dd7c0
Github actions attempt
macobo Oct 29, 2024
709d53e
Faketime
macobo Oct 29, 2024
11dde26
rm playwright_test mix_env
macobo Oct 29, 2024
1bb8a03
docs for util
macobo Oct 29, 2024
e7ef446
Play with screenshots
macobo Oct 29, 2024
aa92b56
Always update snapshots
macobo Oct 29, 2024
5779f77
no modal screenshots
macobo Oct 29, 2024
1b56fe9
Disable changelog
macobo Oct 29, 2024
b7c3241
try pushing again
macobo Oct 29, 2024
7040b2f
Hardcode /changes.txt route
macobo Oct 29, 2024
aaf211d
Experiment with lost pixel
macobo Oct 29, 2024
a7455c9
Remove committing of snapshots
macobo Oct 29, 2024
ab8f219
Alternative screenshot method
macobo Oct 29, 2024
def93c0
Fixed seed for tests
macobo Oct 29, 2024
2a3f989
Fix config
macobo Oct 29, 2024
6066622
Add concurrency
macobo Oct 29, 2024
e66dd3a
Log used seed
macobo Oct 29, 2024
794acab
Different seed
macobo Oct 29, 2024
d08637a
rm logs
macobo Oct 29, 2024
a749cfc
Make seeds the same by not starting app
macobo Oct 29, 2024
259fc18
Deterministic seeds with startup?
macobo Oct 29, 2024
a25ba78
Hardcode list of words
macobo Oct 29, 2024
c9ed0ce
Update action
macobo Oct 30, 2024
684443a
Allow generating slightly future data
macobo Oct 30, 2024
70f899d
Update screenshot options
macobo Oct 30, 2024
009a689
Pseudorandom during seeding
macobo Oct 31, 2024
96ae15e
use apt-get over apt
macobo Oct 31, 2024
e729e4b
Use Plausible.Random more
macobo Oct 31, 2024
5867ea6
Dont screenshot realtime due to timing-sensitivity
macobo Oct 31, 2024
15f61ff
Tweak
macobo Oct 31, 2024
46ad5f8
Tweak more
macobo Oct 31, 2024
ca9c552
Ignore snapshots
macobo Oct 31, 2024
a1fecd5
Improve wording
macobo Oct 31, 2024
98669f6
Solve npm warnings
macobo Oct 31, 2024
55a4974
format
macobo Oct 31, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/elixir.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Elixir CI

on:
pull_request:
# pull_request:
push:
branches: [master, stable]
merge_group:
Expand Down
107 changes: 107 additions & 0 deletions .github/workflows/playwright-e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
name: Playwright CI

on:
pull_request:
push:
branches: [master, stable]
merge_group:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
CACHE_VERSION: v1
PERSISTENT_CACHE_DIR: cached
CI: "true"
MIX_ENV: dev
IP_GEOLOCATION_DB: test/priv/GeoLite2-City-Test.mmdb
RANDOM_SEED: "0"

jobs:
e2e:
name: E2E playwright tests
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16
ports:
- 5432:5432
env:
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
clickhouse:
image: clickhouse/clickhouse-server:24.8.5.115-alpine
ports:
- 8123:8123
env:
options: >-
--health-cmd nc -zw3 localhost 8124
--health-interval 10s
--health-timeout 5s
--health-retries 5

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- uses: marocchino/tool-versions-action@v1
id: versions

- uses: erlef/setup-beam@v1
with:
elixir-version: ${{ steps.versions.outputs.elixir }}
otp-version: ${{ steps.versions.outputs.erlang }}

- uses: actions/setup-node@v4
with:
node-version: ${{ steps.versions.outputs.nodejs }}

- run: sudo apt-get install faketime

- uses: actions/cache@v4
id: cache
with:
path: |
deps
_build
tracker/node_modules
priv/tracker/js
assets/node_modules
~/.cache/ms-playwright
${{ env.PERSISTENT_CACHE_DIR }}
key: playwright-${{ env.CACHE_VERSION }}-${{ github.head_ref || github.ref }}-${{ hashFiles('**/mix.lock') }}
restore-keys: |
playwright-${{ env.CACHE_VERSION }}-${{ github.head_ref || github.ref }}-
playwright-${{ env.CACHE_VERSION }}-refs/heads/master-
playwright-${{ env.CACHE_VERSION }}-

- name: Install frontend dependencies
run: npm ci --prefix assets
- name: Install Playwright Browsers
if: steps.cache.outputs.cache-hit != 'true'
run: npm run playwright:install --prefix assets

- run: mix deps.get

- name: Setup and seed database
run: |
mix ecto.create
mix ecto.migrate
faketime -f "@2024-10-01 00:00:00" mix ecto.setup

- run: mix run -e "Tzdata.ReleaseUpdater.poll_for_update"

- name: Run Playwright tests
run: |
faketime -f "@2024-10-01 00:00:00" npm run playwright --prefix assets

- name: Lost Pixel
uses: lost-pixel/[email protected]
env:
LOST_PIXEL_API_KEY: ${{ secrets.LOST_PIXEL_API_KEY }}
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ npm-debug.log
# test coverage directory
/assets/coverage

# Playwright assets
/assets/playwright-tests/.auth
/assets/playwright-tests/snapshots
/assets/test-results/
/assets/playwright-report/
/assets/blob-report/

# Since we are building assets from assets/,
# we ignore priv/static. You may want to comment
# this depending on your deployment strategy.
Expand Down
16 changes: 16 additions & 0 deletions assets/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Plausible frontend

## Testing

### 1. Jest component tests

React component tests can be run via `npm run test` or `npx jest`. These tests test individual react components using
[@testing-library/react](https://testing-library.com/)

### 2. Playwright tests

Playwright tests test the application end-to-end. Used to test interaction-heavy parts of Plausible like the dashboard.

Locally, the best way to run these tests is to:
1. Reset the database and re-seed: `mix ecto.reset`
2. Run tests in UI mode: `npm run --prefix assets playwright:ui`
2 changes: 1 addition & 1 deletion assets/js/dashboard/components/dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const ToggleDropdownButton = forwardRef<
currentOption: ReactNode
children: ReactNode
onClick: () => void
dropdownContainerProps: AriaAttributes
dropdownContainerProps: AriaAttributes & { 'data-testid'?: string }
}
>(({ currentOption, children, onClick, dropdownContainerProps }, ref) => {
return (
Expand Down
3 changes: 2 additions & 1 deletion assets/js/dashboard/datepicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,8 @@ export default function QueryPeriodPicker() {
onClick={toggleDateMenu}
dropdownContainerProps={{
['aria-controls']: 'datemenu',
['aria-expanded']: menuVisible === 'datemenu'
['aria-expanded']: menuVisible === 'datemenu',
['data-testid']: 'date-menu-button'
}}
>
{menuVisible === 'datemenu' && (
Expand Down
4 changes: 2 additions & 2 deletions assets/js/dashboard/stats/behaviours/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ export default function Behaviours({ importedDataInView }) {
}

return (
<div className={className} onClick={setTab}>
<div className={className} onClick={setTab} role="button" tabIndex={0}>
{displayName}
</div>
)
Expand Down Expand Up @@ -353,7 +353,7 @@ export default function Behaviours({ importedDataInView }) {

if (mode) {
return (
<div className="items-start justify-between block w-full mt-6 md:flex">
<div className="items-start justify-between block w-full mt-6 md:flex" data-testid="section::behaviors">
<div className="w-full p-4 bg-white rounded shadow-xl dark:bg-gray-825">
<div className="flex justify-between w-full">
<div className="flex gap-x-1">
Expand Down
2 changes: 1 addition & 1 deletion assets/js/dashboard/stats/devices/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@ export default function Devices() {
}

return (
<div>
<div data-testid="section::devices">
<div className="flex justify-between w-full">
<div className="flex gap-x-1">
<h3 className="font-bold dark:text-gray-100">Devices</h3>
Expand Down
2 changes: 1 addition & 1 deletion assets/js/dashboard/stats/graph/visitor-graph.js
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ export default function VisitorGraph({ updateImportedDataInView }) {
<div className={"relative w-full mt-2 bg-white rounded shadow-xl dark:bg-gray-825"}>
{(topStatsLoading || graphLoading) && renderLoader()}
<FadeIn show={!(topStatsLoading || graphLoading)}>
<div id="top-stats-container" className="flex flex-wrap" ref={topStatsBoundary} style={{ height: getTopStatsHeight() }}>
<div id="top-stats-container" className="flex flex-wrap" ref={topStatsBoundary} style={{ height: getTopStatsHeight() }} data-testid="section::top-stats">
<TopStats
data={topStatData}
onMetricUpdate={onMetricUpdate}
Expand Down
4 changes: 2 additions & 2 deletions assets/js/dashboard/stats/locations/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ class Locations extends React.Component {

render() {
return (
<div>
<div data-testid="section::locations">
<div className="w-full flex justify-between">
<div className="flex gap-x-1">
<h3 className="font-bold dark:text-gray-100">
Expand All @@ -257,4 +257,4 @@ function LocationsWithContext() {
const site = useSiteContext();
return <Locations site={site} query={query} />
}
export default LocationsWithContext
export default LocationsWithContext
3 changes: 2 additions & 1 deletion assets/js/dashboard/stats/modals/breakdown-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,8 @@ export default function BreakdownModal<TListItem extends { name: string }>({
orderByDictionary,
toggleSortByMetric,
renderIcon,
getExternalLinkURL
getExternalLinkURL,
meta
]
)

Expand Down
1 change: 1 addition & 0 deletions assets/js/dashboard/stats/more-link.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export default function MoreLink({ linkProps, list, className, onClick }) {
{...linkProps}
className="leading-snug font-bold text-sm text-gray-500 dark:text-gray-400 hover:text-red-500 dark:hover:text-red-400 transition tracking-wide"
onClick={onClick}
data-testid="details-link"
>
{detailsIcon()}
DETAILS
Expand Down
2 changes: 1 addition & 1 deletion assets/js/dashboard/stats/pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ export default function Pages() {
}

return (
<div>
<div data-testid="section::pages">
{/* Header Container */}
<div className="w-full flex justify-between">
<div className="flex gap-x-1">
Expand Down
6 changes: 5 additions & 1 deletion assets/js/dashboard/stats/reports/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,11 @@ export default function ListReport({

return (
<LazyLoader onVisible={onVisible}>
<div className="w-full" style={{ minHeight: `${MIN_HEIGHT}px` }}>
<div
className="w-full"
style={{ minHeight: `${MIN_HEIGHT}px` }}
data-testid={`list-report::${keyLabel}`}
>
{state.loading && renderLoading()}
{!state.loading && (
<FadeIn show={!state.loading} className="h-full">
Expand Down
2 changes: 1 addition & 1 deletion assets/js/dashboard/stats/sources/referrer-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export default function Referrers({ source }) {
}

return (
<div className="flex flex-col flex-grow">
<div className="flex flex-col flex-grow" data-testid="section::sources">
<div className="flex gap-x-1">
<h3 className="font-bold dark:text-gray-100">Top Referrers</h3>
<ImportedQueryUnsupportedWarning loading={loading} skipImportedReason={skipImportedReason} />
Expand Down
2 changes: 1 addition & 1 deletion assets/js/dashboard/stats/sources/search-terms.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ export default class SearchTerms extends React.Component {

render() {
return (
<div>
<div data-testid="section::sources">
{this.state.loading && <div className="loading mt-44 mx-auto"><div></div></div>}
<FadeIn show={!this.state.loading} className="flex-grow">
<LazyLoader onVisible={this.onVisible}>
Expand Down
6 changes: 3 additions & 3 deletions assets/js/dashboard/stats/sources/source-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ export default function SourceList() {

<Menu as="div" className="relative inline-block text-left">
<div>
<Menu.Button className="inline-flex justify-between focus:outline-none">
<Menu.Button className="inline-flex justify-between focus:outline-none" data-testid="campaign-menu">
<span className={currentTab.startsWith('utm_') ? activeClass : defaultClass}>{buttonText}</span>
<ChevronDownIcon className="-mr-1 ml-1 h-4 w-4" aria-hidden="true" />
</Menu.Button>
Expand All @@ -198,7 +198,7 @@ export default function SourceList() {
<div className="py-1">
{dropdownOptions.map((option) => {
return (
<Menu.Item key={option}>
<Menu.Item key={option} name={UTM_TAGS[option].label}>
{({ active }) => (
<span
onClick={setTab(option)}
Expand Down Expand Up @@ -238,7 +238,7 @@ export default function SourceList() {
}

return (
<div>
<div data-testid="section::sources">
{/* Header Container */}
<div className="w-full flex justify-between">
<div className="flex gap-x-1">
Expand Down
Loading
Loading