From afd30e3e017331379743dcf590db167aa822ed9c Mon Sep 17 00:00:00 2001 From: Marcello Fuschi Date: Mon, 3 Jun 2024 20:23:17 -0300 Subject: [PATCH 1/2] Use a real account for the demo experience (#485) * Use a real account for the demo experience * Update puppeteer tests --- README.md | 2 +- src/App.jsx | 3 +-- src/__puppeteer__/demo.test.js | 3 ++- src/__puppeteer__/drive.test.js | 10 +++++++--- src/__puppeteer__/offline.test.js | 22 ---------------------- src/__puppeteer__/routing.test.js | 13 ++++++------- src/actions/startup.js | 10 ---------- src/analytics.js | 4 ---- src/components/Navigation/index.jsx | 7 +------ src/components/anonymous.jsx | 12 +++++++----- src/demo/devices.json | 13 ------------- src/demo/index.js | 16 ---------------- src/demo/profile.json | 10 ---------- src/initialState.js | 8 -------- 14 files changed, 25 insertions(+), 108 deletions(-) delete mode 100644 src/__puppeteer__/offline.test.js delete mode 100644 src/demo/devices.json delete mode 100644 src/demo/index.js delete mode 100644 src/demo/profile.json diff --git a/README.md b/README.md index 6d35b8ade..ff30024fc 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ The frontend to the comma connect progressive web app. This a react app using [C ## Contributing -If you don't have a comma device, connect has a demo mode with an example drive. This should allow for testing most functionality except for interactions with the device, such as getting the car battery voltage. +If you don't have a comma device, connect has a demo mode with some example drives. This should allow for testing most functionality except for interactions with the device, such as getting the car battery voltage. * Use best practices * Write test cases diff --git a/src/App.jsx b/src/App.jsx index 3ab880f39..1ea21aa4c 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -12,7 +12,6 @@ import MyCommaAuth, { config as AuthConfig, storage as AuthStorage } from '@comm import { athena as Athena, auth as Auth, billing as Billing, request as Request } from '@commaai/api'; import { getZoom } from './url'; -import { isDemo } from './demo'; import store, { history } from './store'; import ErrorFallback from './components/ErrorFallback'; @@ -123,7 +122,7 @@ class App extends Component { return this.renderLoading(); } - const showLogin = !MyCommaAuth.isAuthenticated() && !isDemo() && !getZoom(window.location.pathname); + const showLogin = !MyCommaAuth.isAuthenticated() && !getZoom(window.location.pathname); let content = ( { showLogin ? this.anonymousRoutes() : this.authRoutes() } diff --git a/src/__puppeteer__/demo.test.js b/src/__puppeteer__/demo.test.js index 2feb0ee99..7ff18420a 100644 --- a/src/__puppeteer__/demo.test.js +++ b/src/__puppeteer__/demo.test.js @@ -9,7 +9,8 @@ describe('demo mode', () => { }); it('should load demo route', async () => { - await goto('/a2a0ccea32023010', { waitUntil: 'networkidle2' }); + await goto('/'); + await page.click('xpath=//a[contains(string(), "Try the demo")]'); await page.waitForSelector('.DriveList'); await page.waitForSelector('.DriveEntry'); diff --git a/src/__puppeteer__/drive.test.js b/src/__puppeteer__/drive.test.js index ba423fdf0..55528fd2b 100644 --- a/src/__puppeteer__/drive.test.js +++ b/src/__puppeteer__/drive.test.js @@ -1,15 +1,19 @@ /* eslint-env jest */ import { configureViewport, goto } from './utils'; -const DEMO_DEVICE_URL = '/4cf7a6ad03080c90'; -const DEMO_ROUTE_URL = '/4cf7a6ad03080c90/1632948396703/1632949028503'; -const ZOOMED_DEMO_URL = '/4cf7a6ad03080c90/1632948397703/1632949027503'; +const DEMO_DEVICE_URL = '/1d3dc3e03047b0c7'; +const DEMO_ROUTE_URL = '/1d3dc3e03047b0c7/1716484475499/1716485004466'; +const ZOOMED_DEMO_URL = '/1d3dc3e03047b0c7/1716484476499/1716485003466'; jest.setTimeout(60000); describe('drive view', () => { beforeAll(async () => { await configureViewport(); + + // Log in to demo account + await goto('/'); + await page.click('xpath=//a[contains(string(), "Try the demo")]'); }); it('back button disabled when in route bounds', async () => { diff --git a/src/__puppeteer__/offline.test.js b/src/__puppeteer__/offline.test.js deleted file mode 100644 index e0e722365..000000000 --- a/src/__puppeteer__/offline.test.js +++ /dev/null @@ -1,22 +0,0 @@ -/* eslint-env jest */ -import { configureViewport, goto } from './utils'; - -jest.setTimeout(30000); - -describe('offline', () => { - beforeAll(async () => { - await configureViewport(); - }); - - it('should not crash when navigating while offline', async () => { - await goto('/a2a0ccea32023010'); - await page.waitForSelector('.DriveEntry'); - - await page.setOfflineMode(true); - await page.setCacheEnabled(false); - await page.reload({ waitUntil: 'networkidle0' }); - - expect(await page.$x('//*[contains(string(), "Corolla")]')).toBeTruthy(); - expect(await page.$x('//*[contains(string(), "Loading...")]')).toBeTruthy(); - }); -}); diff --git a/src/__puppeteer__/routing.test.js b/src/__puppeteer__/routing.test.js index 130b44035..0839dfe56 100644 --- a/src/__puppeteer__/routing.test.js +++ b/src/__puppeteer__/routing.test.js @@ -6,26 +6,25 @@ jest.setTimeout(30000); describe('routing', () => { beforeAll(async () => { await configureViewport(); - }); - it('login page', async () => { + // Log in to demo account await goto('/'); - await page.waitForXPath('//*[contains(string(), "Try the demo")]'); + await page.click('xpath=//a[contains(string(), "Try the demo")]'); }); it('load route list', async () => { - await goto('/a2a0ccea32023010'); + await goto('/1d3dc3e03047b0c7'); await page.waitForSelector('.DriveList'); await page.waitForSelector('.DriveEntry'); - // Page should have one ".DriveEntry" element + // Page should have at least one ".DriveEntry" element const driveEntries = await page.$$('.DriveEntry'); - expect(driveEntries.length).toBe(1); + expect(driveEntries.length).toBeGreaterThanOrEqual(1); }); it('load route from URL', async () => { - await goto('/a2a0ccea32023010/1690488081496/1690488851596', { timeout: 50000 }); + await goto('/1d3dc3e03047b0c7/1716484475499/1716485004466', { timeout: 50000 }); // Wait for video src to be set await page.waitForFunction( diff --git a/src/actions/startup.js b/src/actions/startup.js index 4f1fc366f..a2bef7531 100644 --- a/src/actions/startup.js +++ b/src/actions/startup.js @@ -2,13 +2,9 @@ import * as Sentry from '@sentry/react'; import { account as Account, devices as Devices } from '@commaai/api'; import MyCommaAuth from '@commaai/my-comma-auth'; -import * as Demo from '../demo'; import { ACTION_STARTUP_DATA } from './types'; import { primeFetchSubscription, checkRoutesData, selectDevice, fetchSharedDevice } from '.'; -import demoProfile from '../demo/profile.json'; -import demoDevices from '../demo/devices.json'; - async function initProfile() { if (MyCommaAuth.isAuthenticated()) { try { @@ -21,8 +17,6 @@ async function initProfile() { Sentry.captureException(err, { fingerprint: 'init_api_get_profile' }); } } - } else if (Demo.isDemo()) { - return demoProfile; } return null; } @@ -30,10 +24,6 @@ async function initProfile() { async function initDevices() { let devices = []; - if (Demo.isDemo()) { - devices = devices.concat(demoDevices); - } - if (MyCommaAuth.isAuthenticated()) { try { devices = devices.concat(await Devices.listDevices()); diff --git a/src/analytics.js b/src/analytics.js index 4b78f5df8..4f7db894a 100644 --- a/src/analytics.js +++ b/src/analytics.js @@ -7,7 +7,6 @@ import * as Types from './actions/types'; import { sendEvent } from './analytics-v2'; import { getDongleID, getZoom } from './url'; import { deviceIsOnline } from './utils'; -import { isDemoDevice } from './demo'; function getPageViewEventLocation(pathname) { let pageLocation = pathname; @@ -129,7 +128,6 @@ function logAction(action, prevState, state) { superuser: state.profile?.superuser, has_prime: state.profile?.prime, devices_count: state.devices?.length, - device_is_demo: isDemoDevice(state.device?.dongle_id), device_prime_type: state.device?.prime_type, device_type: state.device?.device_type, device_version: state.device?.openpilot_version, @@ -154,7 +152,6 @@ function logAction(action, prevState, state) { case Types.ACTION_SELECT_DEVICE: gtag('event', 'select_device', { ...params, - device_is_demo: isDemoDevice(state.device?.dongle_id), device_prime_type: state.device?.prime_type, device_type: state.device?.device_type, device_version: state.device?.openpilot_version, @@ -171,7 +168,6 @@ function logAction(action, prevState, state) { gtag('set', { user_properties: { - device_is_demo: isDemoDevice(state.device?.dongle_id), device_prime_type: state.device?.prime_type, device_type: state.device?.device_type, device_version: state.device?.openpilot_version, diff --git a/src/components/Navigation/index.jsx b/src/components/Navigation/index.jsx index 9113cbf5b..4ebfc2355 100644 --- a/src/components/Navigation/index.jsx +++ b/src/components/Navigation/index.jsx @@ -13,7 +13,6 @@ import { athena as Athena, devices as Devices, navigation as NavigationApi } fro import { primeNav, analyticsEvent } from '../../actions'; import { DEFAULT_LOCATION, forwardLookup, getDirections, MAPBOX_STYLE, MAPBOX_TOKEN, networkPositioning, reverseLookup } from '../../utils/geocode'; import Colors from '../../colors'; -import * as Demo from '../../demo'; import { PinCarIcon, PinMarkerIcon, PinHomeIcon, PinWorkIcon, PinPinnedIcon } from '../../icons'; import { timeFromNow } from '../../utils'; import ResizeHandler from '../ResizeHandler'; @@ -395,10 +394,6 @@ class Navigation extends Component { } updateDevice() { - if (Demo.isDemo()) { - return; - } - this.getDeviceLastLocation(); this.getDeviceNetworkLocation(); this.updateFavoriteLocations(); @@ -480,7 +475,7 @@ class Navigation extends Component { updateFavoriteLocations() { const { dongleId, hasNav } = this.props; - if (!hasNav || Demo.isDemo()) { + if (!hasNav) { return; } diff --git a/src/components/anonymous.jsx b/src/components/anonymous.jsx index 0d292f67d..6d5889a06 100644 --- a/src/components/anonymous.jsx +++ b/src/components/anonymous.jsx @@ -9,15 +9,13 @@ import qs from 'query-string'; import { withStyles } from '@material-ui/core/styles'; import Typography from '@material-ui/core/Typography'; -import { config as AuthConfig } from '@commaai/my-comma-auth'; +import {config as AuthConfig, storage as AuthStorage} from '@commaai/my-comma-auth'; import Colors from '../colors'; import { AuthAppleIcon, AuthGithubIcon, AuthGoogleIcon, RightArrow } from '../icons'; import PWAIcon from './PWAIcon'; -import demoDevices from '../demo/devices.json'; - const styles = () => ({ baseContainer: { width: '100%', @@ -130,6 +128,11 @@ class AnonymousLanding extends Component { render() { const { classes } = this.props; + const loginAsDemoUser = function() { + AuthStorage.setCommaAccessToken('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NDg1ODI0NjUsIm5iZiI6MTcxNzA0NjQ2NSwiaWF0IjoxNzE3MDQ2NDY1LCJpZGVudGl0eSI6IjBkZWNkZGNmZGYyNDFhNjAifQ.g3khyJgOkNvZny6Vh579cuQj1HLLGSDeauZbfZri9jw'); + window.location = window.location.origin; + }; + return (
@@ -159,9 +162,8 @@ class AnonymousLanding extends Component { paired your comma device. - Try the demo diff --git a/src/demo/devices.json b/src/demo/devices.json deleted file mode 100644 index 86749ba77..000000000 --- a/src/demo/devices.json +++ /dev/null @@ -1,13 +0,0 @@ -[ - { - "alias": "Corolla", - "device_type": "three", - "dongle_id": "a2a0ccea32023010", - "ignore_uploads": null, - "is_owner": false, - "shared": true, - "is_paired": true, - "last_athena_ping": 1691040268, - "sim_id": "0000000000000000000" - } -] diff --git a/src/demo/index.js b/src/demo/index.js deleted file mode 100644 index de64bbfff..000000000 --- a/src/demo/index.js +++ /dev/null @@ -1,16 +0,0 @@ -import demoDevices from './devices.json'; - -export function isDemoDevice(dongleId) { - return demoDevices.some((d) => d.dongle_id === dongleId); -} - -export function isDemoRoute(route) { - return route === 'a2a0ccea32023010|2023-07-27--13-01-19'; -} - -export function isDemo() { - if (!window.location || !window.location.pathname) { - return false; - } - return isDemoDevice(window.location.pathname.split('/')[1]); -} diff --git a/src/demo/profile.json b/src/demo/profile.json deleted file mode 100644 index 420ba11e2..000000000 --- a/src/demo/profile.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "email": "commaexplorer@gmail.com", - "id": "8ca5365277ebc093", - "points": 7857, - "prime": false, - "regdate": 1542645991, - "superuser": false, - "upload_video": false, - "username": "commaexplorer" -} diff --git a/src/initialState.js b/src/initialState.js index ff6b7ac11..caefd0c02 100644 --- a/src/initialState.js +++ b/src/initialState.js @@ -1,17 +1,9 @@ import { getDongleID, getZoom, getPrimeNav } from './url'; -import * as Demo from './demo'; export function getDefaultFilter() { const d = new Date(); d.setHours(d.getHours() + 1, 0, 0, 0); - if (Demo.isDemo()) { - return { - start: 1690488081496, - end: 1690488851596, - }; - } - return { start: (new Date(d.getTime() - 1000 * 60 * 60 * 24 * 14)).getTime(), end: d.getTime(), From 2c3fe68c3e3f42fe9ceceabd77c6b47f3a4e2125 Mon Sep 17 00:00:00 2001 From: Marcello Fuschi Date: Tue, 4 Jun 2024 01:22:03 -0300 Subject: [PATCH 2/2] Fix typo in README (#488) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ff30024fc..91379b387 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ There's a ton of them, but these are worth mentioning because they sort of affec * `@material-ui` - Lots of fully featured highly customizable components for building the UIs with. Theming system with global and per-component overrides of any CSS values. * `react-router-redux` - the newer one, 5.x.... Mindlessly simple routing with convenient global access due to redux -## How things works +## How things work The current playback is tracked not by storing the current offset, but instead storing the local time that the player began, the offset it began at, and the playback rate. Any time any of these values change, it rebases them all back to the current time. It means that at any arbitrary moment you can calculate the current offset with... ```js (Date.now() - state.startTime) * state.playSpeed + state.offset