all repos — caroster @ 9079b470260a87959da56f303e6682211cb847d1

[Octree] Group carpool to your event https://caroster.io

:wheelchair: Add accessibility car edition
Hadrien Froger e3k8y9i0k3s8o9x4@octreea17.slack.com
Fri, 03 Jul 2020 06:46:21 +0000
commit

9079b470260a87959da56f303e6682211cb847d1

parent

9706a05b8adf4b0adf97299733cfd9ea2c457a62

M app/src/containers/Car/Header.jsapp/src/containers/Car/Header.js

@@ -11,19 +11,27 @@ const classes = useStyles();

const {t} = useTranslation(); return ( <div className={classes.header}> - <IconButton className={classes.editBtn} onClick={toggleEditing}> + <IconButton + className={classes.editBtn} + onClick={toggleEditing} + id="EditCarBtn" + > <Icon>edit</Icon> </IconButton> {!!car.departure && ( - <Typography variant="overline"> + <Typography variant="overline" id="CarDeparture"> {moment(car.departure).format('LLLL')} </Typography> )} - <Typography variant="h5">{car.name}</Typography> + <Typography variant="h5" id="CarName"> + {car.name} + </Typography> {!!car.phone_number && ( <div className={classes.section}> <Typography variant="subtitle2">{t('car.fields.phone')}</Typography> - <Typography variant="body2">{car.phone_number}</Typography> + <Typography variant="body2" id="CarPhone"> + {car.phone_number} + </Typography> </div> )} {!!car.meeting && (

@@ -31,13 +39,17 @@ <div className={classes.section}>

<Typography variant="subtitle2"> {t('car.fields.meeting_point')} </Typography> - <Typography variant="body2">{car.meeting}</Typography> + <Typography variant="body2" id="CarMeeting"> + {car.meeting} + </Typography> </div> )} {!!car.details && ( <div className={classes.section}> <Typography variant="subtitle2">{t('car.fields.details')}</Typography> - <Typography variant="body2">{car.details}</Typography> + <Typography variant="body2" id="CarDetails"> + {car.details} + </Typography> </div> )} </div>
M app/src/containers/Car/HeaderEditing.jsapp/src/containers/Car/HeaderEditing.js

@@ -1,4 +1,4 @@

-import React, {useState, useReducer} from 'react'; +import React, {useState, useReducer, useCallback, useEffect} from 'react'; import Typography from '@material-ui/core/Typography'; import IconButton from '@material-ui/core/IconButton'; import Icon from '@material-ui/core/Icon';

@@ -32,7 +32,23 @@ );

const [phone, setPhone] = useState(car?.phone_number ?? ''); const [details, setDetails] = useState(car?.details ?? ''); - const onSave = async () => { + // Click on ESQ should close the form + const escFunction = useCallback( + evt => { + if (evt.keyCode === 27) toggleEditing(); + }, + [toggleEditing] + ); + + useEffect(() => { + document.addEventListener('keydown', escFunction, false); + return () => { + document.removeEventListener('keydown', escFunction, false); + }; + }, [escFunction]); + + const onSave = async evt => { + if (evt.preventDefault) evt.preventDefault(); try { // If new seats count is under current passengers count, put excedent in event waiting list if (!!car.passengers && car.passengers.length > seats) {

@@ -57,6 +73,7 @@ } catch (error) {

console.error(error); addToast('car.errors.cant_update'); } + return false; }; const onRemove = async () => {

@@ -78,83 +95,91 @@ };

return ( <div className={classes.header}> - <IconButton className={classes.editBtn} onClick={onSave}> - <Icon>done</Icon> - </IconButton> - <DateTimePicker - label={t('event.creation.date')} - value={date} - onChange={setDate} - className={classes.textField} - fullWidth - format="LLLL" - disablePast - id="UpdateCarDateTime" - name="date" - /> - <TextField - className={classes.textField} - label={t('car.creation.name')} - fullWidth - autoFocus - margin="dense" - value={name} - onChange={e => setName(e.target.value)} - id="UpdateCarName" - name="name" - /> - <TextField - className={classes.textField} - label={t('car.creation.phone')} - fullWidth - autoFocus - margin="dense" - value={phone} - onChange={e => setPhone(e.target.value)} - id="UpdateCarPhone" - name="phone" - /> - <TextField - className={classes.textField} - label={t('car.creation.meeting')} - fullWidth - margin="dense" - multiline - rows={2} - value={meeting} - onChange={e => setMeeting(e.target.value)} - id="UpdateCarMeeting" - name="meeting" - /> - <TextField - className={classes.textField} - label={t('car.creation.notes')} - fullWidth - margin="dense" - multiline - rows={2} - value={details} - onChange={e => setDetails(e.target.value)} - id="UpdateCarDetails" - name="details" - /> - <div className={classes.slider}> - <Typography variant="caption">{t('car.creation.seats')}</Typography> - <Slider - value={seats} - onChange={(e, value) => setSeats(value)} - step={1} - marks={[1, 2, 3, 4, 5, 6, 7, 8].map(value => ({ - value, - label: value, - }))} - min={1} - max={8} - valueLabelDisplay="auto" + <form onSubmit={onSave}> + <IconButton type="submit" className={classes.editBtn}> + <Icon>done</Icon> + </IconButton> + <DateTimePicker + label={t('event.creation.date')} + value={date} + onChange={setDate} + className={classes.textField} + fullWidth + format="LLLL" + disablePast + id="EditCarDateTime" + name="date" + /> + <TextField + className={classes.textField} + label={t('car.creation.name')} + fullWidth + autoFocus + margin="dense" + value={name} + onChange={e => setName(e.target.value)} + id="EditCarName" + name="name" + /> + <TextField + className={classes.textField} + label={t('car.creation.phone')} + fullWidth + autoFocus + margin="dense" + value={phone} + onChange={e => setPhone(e.target.value)} + id="EditCarPhone" + name="phone" + /> + <TextField + className={classes.textField} + label={t('car.creation.meeting')} + fullWidth + margin="dense" + multiline + rows={2} + value={meeting} + onChange={e => setMeeting(e.target.value)} + id="EditCarMeeting" + name="meeting" + /> + <TextField + className={classes.textField} + label={t('car.creation.notes')} + fullWidth + margin="dense" + multiline + rows={2} + value={details} + onChange={e => setDetails(e.target.value)} + id="EditCarDetails" + name="details" /> - </div> + <div className={classes.slider}> + <Typography variant="caption">{t('car.creation.seats')}</Typography> + <Slider + value={seats} + onChange={(e, value) => setSeats(value)} + step={1} + marks={[1, 2, 3, 4, 5, 6, 7, 8].map(value => ({ + value, + label: value, + }))} + min={1} + max={8} + valueLabelDisplay="auto" + id="EditCarSeats" + /> + </div> + </form> <div className={classes.actions}> - <Button color="secondary" variant="outlined" onClick={toggleRemoving}> + <Button + color="secondary" + variant="outlined" + onClick={toggleRemoving} + id="CarRemove" + > {t('car.actions.remove')} </Button> </div>
M app/src/containers/Car/RemoveDialog.jsapp/src/containers/Car/RemoveDialog.js

@@ -20,8 +20,11 @@ <DialogContent>

<DialogContentText>{t('car.actions.remove_alert')}</DialogContentText> </DialogContent> <DialogActions> - <Button onClick={toggle}>{t('generic.cancel')}</Button> + <Button onClick={toggle} id="CarRemoveCancel"> + {t('generic.cancel')} + </Button> <Button + id="CarRemoveConfirm" onClick={() => { onRemove(); toggle();
M e2e/bin/deploye2e/bin/deploy

@@ -7,5 +7,6 @@ kubectl cp ./reports/screenshots caroster-test/$POD:/usr/share/nginx/html/ --namespace caroster-test

kubectl cp ./reports/videos caroster-test/$POD:/usr/share/nginx/html/ --namespace caroster-test kubectl cp ./reports/allure-report caroster-test/$POD:/usr/share/nginx/html/ --namespace caroster-test kubectl cp ./reports/index.html caroster-test/$POD:/usr/share/nginx/html/index.html --namespace caroster-test +kubectl cp ./reports/test caroster-test/$POD:/usr/share/nginx/html/ --namespace caroster-test echo "done"
M e2e/conf/chrome.jse2e/conf/chrome.js

@@ -50,7 +50,7 @@ colors: true,

snippets: true, source: true, profile: [], - strict: true, + strict: false, tags: [], timeout: 100000, ignoreUndefinedDefinitions: false,
M e2e/hooks/index.jse2e/hooks/index.js

@@ -46,6 +46,13 @@ type: 'test',

}; console.log('start recording'); await cmds.startScreenRecording(test); + + const oldBaseURL = browser.options.baseUrl; + browser.options.baseUrl = 'https://caroster-page.dev.octr.ee'; + await browser.url(`/${feature.uri}.txt`); + console.log('browse ', browser.options.baseUrl, `/${feature.uri}`); + browser.options.baseUrl = oldBaseURL; + await new Promise(resolve => setTimeout(resolve, 5000)); }, afterFeature: async function (uri, feature, scenarios) { const name = slugify(feature.document.feature.name);
M e2e/package-lock.jsone2e/package-lock.json

@@ -6427,6 +6427,15 @@ "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",

"integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", "optional": true }, + "path": { + "version": "0.12.7", + "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", + "integrity": "sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=", + "requires": { + "process": "^0.11.1", + "util": "^0.10.3" + } + }, "path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",

@@ -6592,6 +6601,11 @@ "version": "0.1.8",

"resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" }, "process-nextick-args": { "version": "2.0.1",

@@ -7906,6 +7920,21 @@ "version": "3.1.1",

"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", "optional": true + }, + "util": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz", + "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==", + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } }, "util-arity": { "version": "1.1.0",
M e2e/package.jsone2e/package.json

@@ -18,6 +18,7 @@ "axios": "^0.19.2",

"faker": "^4.1.0", "mailhog": "4", "mocha": "^8.0.1", + "path": "^0.12.7", "pug": "^3.0.0", "slugify": "^1.4.4", "uuid": "8",
M e2e/reports/.gitignoree2e/reports/.gitignore

@@ -1,4 +1,5 @@

* !index.html !screenshots.js +!gerkhins.js !/.gitignore
A e2e/reports/gerkhins.js

@@ -0,0 +1,25 @@

+var fs = require('fs'); +const path = require('path'); +var walk = function (dir) { + var results = []; + var list = fs.readdirSync(dir); + list.forEach(function (file) { + var fileItem = dir + '/' + file; + var stat = fs.statSync(fileItem); + if (stat && stat.isDirectory()) { + /* Recurse into a subdirectory */ + results = results.concat(walk(fileItem)); + } else { + /* Is a file */ + results.push(fileItem); + } + }); + return results; +}; + +walk('./test/features').forEach(filePath => { + const targetDir = './reports/' + path.dirname(filePath); + fs.mkdirSync(targetDir, {recursive: true}); + + fs.copyFileSync(filePath, targetDir + '/' + path.basename(filePath) + '.txt'); +});
A e2e/test/features/Cars/EditCar.feature

@@ -0,0 +1,21 @@

+@GIT.6 and @skip +Feature: Car Update + Background: + Given I am vistor + And I have created an event + And I have created a car + Scenario: I can update a car + When I am on the event page + And I edit my car + And I write Edited in car name field + And I pick 6 in car seats field + And I write Edited in car meeting field + And I write Edited in car meeting field + + And I type my car name + And I pick my car seats + And I type my car meeting + And I type my car event date + And I type my phone + And I type my car details + And I submit the form
M e2e/test/pages/_page.jse2e/test/pages/_page.js

@@ -86,10 +86,10 @@ const element = await $(field);

await element.click(); } - async waitForDisplayed(timeout = 1200) { + async waitForDisplayed(timeout = 1200, takeScreenshot = true) { await new Promise(resolve => { setTimeout(resolve, timeout); }); - await browser.saveScreenshotByName(this.name); + if (takeScreenshot) await browser.saveScreenshotByName(this.name); } }
M e2e/test/pages/newCar.jse2e/test/pages/newCar.js

@@ -1,4 +1,5 @@

import {Page} from './_page'; +import {EventPage} from './eventPage'; class _NewCar extends Page { /** *

@@ -28,7 +29,7 @@ case 'car details':

case 'my car details': return '#NewCarDetails'; case 'submit': - return 'button.MuiButton-contained'; + return '#NewCarSubmit'; } throw new Error('Unknown selector ' + selector); }

@@ -41,9 +42,10 @@ async submit() {

await new Promise(resolve => { setTimeout(resolve, 3000); }); - await browser.saveScreenshotByName(`${this.name}--filled`); - - // await super.submit(); + await super.submit(); + global.SCENE.scene = EventPage; + await EventPage.waitForDisplayed(undefined, false); + await browser.saveScreenshotByName(`${EventPage.name}--carCreated`); } } export const NewCar = new _NewCar('/');
M e2e/test/pages/newEvent.jse2e/test/pages/newEvent.js

@@ -21,9 +21,9 @@ case 'my email':

return '#NewEventEmail'; case 'on the Tos label': case 'Tos label': - return '.MuiTypography-caption'; + return 'a.MuiTypography-caption'; case 'submit': - return 'button.MuiButton-root'; + return 'button[type="submit"]'; } throw new Error('Unknown selector ' + selector); }