Skip to content

Commit

Permalink
✅ Add Cypress test
Browse files Browse the repository at this point in the history
  • Loading branch information
homostellaris committed Aug 20, 2024
1 parent 65e6d61 commit 5076df0
Show file tree
Hide file tree
Showing 13 changed files with 1,424 additions and 43 deletions.
7 changes: 6 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v3
uses: actions/checkout@v4
- run: npm ci
# TODO: Fix this once we know how to authenticate codegen in CI (or its changed to no longer need that)
# - run: npx convex codegen
# - run: npm run type-check
- run: npm run lint
- run: npm run build
- name: Cypress run
uses: cypress-io/github-action@v6
with:
start: npm start
8 changes: 8 additions & 0 deletions components/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ export class DexieStarfocus extends Dexie {
super('starfocus', {
addons: [dexieCloud],
})
this.on.populate.subscribe(() => {
this.on.ready.subscribe((db: DexieStarfocus) => {
db.lists.put({
type: '#important',
order: [],
})
}, false)
})
this.version(3).stores({
todos: '@id, createdAt, completedAt, starRole, title',
lists: 'type',
Expand Down
31 changes: 19 additions & 12 deletions components/pages/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ const Home = () => {
<IonToolbar>
<IonButtons slot="primary">
<IonButton
id="view-menu-button"
onClick={() => {
menuController.toggle('end')
}}
Expand All @@ -194,7 +195,10 @@ const Home = () => {
/>
</IonButton>
</IonButtons>
<IonButtons slot="start">
<IonButtons
id="misc-menu-button"
slot="start"
>
<IonMenuButton></IonMenuButton>
</IonButtons>
<Searchbar ref={searchbarRef} />
Expand Down Expand Up @@ -226,8 +230,9 @@ export const MiscMenu = () => {

return (
<IonMenu
type="push"
contentId="main-content"
id="misc-menu"
type="push"
>
<IonHeader>
<IonToolbar>
Expand Down Expand Up @@ -354,16 +359,16 @@ export const ViewMenu = () => {
const {
activateStarRole,
activeStarRoles,
allStarRolesActive,
deactivateStarRole,
setActiveStarRoles,
} = useView()

return (
<IonMenu
type="push"
side="end"
contentId="main-content"
id="view-menu"
side="end"
type="push"
>
<IonHeader>
<IonToolbar>
Expand Down Expand Up @@ -470,13 +475,14 @@ export const Log = ({
if (todos === undefined) return null

return (
<>
<section id="log">
<h1>Log</h1>
{todos?.length ? (
<IonList inset>
{todos.sort(byDate).map(todo => (
<IonItem
button
className="todo"
key={todo.id}
onClick={_event => {
present(todo)
Expand Down Expand Up @@ -519,7 +525,7 @@ export const Log = ({
<p>Your completed todos will appear here</p>
</div>
)}
</>
</section>
)
}

Expand Down Expand Up @@ -548,7 +554,7 @@ export const Important = ({ onLoad }: { onLoad: () => void }) => {
if (todos === undefined) return null

return (
<>
<section id="important">
<h1>Important</h1>
{todos?.length && importantList ? (
<IonList inset>
Expand Down Expand Up @@ -579,6 +585,7 @@ export const Important = ({ onLoad }: { onLoad: () => void }) => {
{todos.map(todo => (
<IonItem
button
className="todo"
onClick={event => {
// Prevent the action sheet from opening when reordering
if (event.target['localName'] === 'ion-item') return
Expand Down Expand Up @@ -667,7 +674,7 @@ export const Important = ({ onLoad }: { onLoad: () => void }) => {
<p>Create some todos to get started</p>
</div>
)}
</>
</section>
)
}

Expand Down Expand Up @@ -753,7 +760,7 @@ export const Icebox = ({
if (todos === undefined) return null

return (
<>
<section id="icebox">
<IonGrid>
<h1>Icebox</h1>
<IonRow>
Expand All @@ -773,7 +780,7 @@ export const Icebox = ({
)}
</IonRow>
</IonGrid>
</>
</section>
)
}

Expand All @@ -786,7 +793,7 @@ export const IceboxItem = ({
}) => {
return (
<IonCard
className="cursor-pointer"
className="cursor-pointer todo"
onClick={_event => {
onClick(todo)
}}
Expand Down
2 changes: 2 additions & 0 deletions components/starRoles/StarRoleModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,10 @@ export default function StarRoleModal({
type="text"
value={iconQuery}
>
{/* Conditionally rendering this caused React errors, must be due to implemenation */}
<IonIcon
icon={icon?.value}
id="selected-icon"
slot="end"
/>
</IonInput>
Expand Down
62 changes: 32 additions & 30 deletions components/starRoles/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,38 @@ export default function Icons({
}, [query])

return (
<IonGrid className="relative p-2 border rounded">
<IonRow>
<a
className="absolute p-1 space-x-1 text-xs bg-white right-2 -top-3"
href="https://ionic.io/ionicons"
target="_blank"
>
<span>View all icons</span>
<IonIcon icon={icons.openSharp} />
</a>
{matchingIcons.length ? (
matchingIcons.map(([name, value]) => (
<IonCol
key={name}
size="1"
>
<IonIcon
className="cursor-pointer"
onClick={() => onClick({ name, value })}
icon={value}
></IonIcon>
</IonCol>
))
) : (
<p className="w-full m-2 text-center text-gray-300">
No matching icons
</p>
)}
</IonRow>
</IonGrid>
<div className="relative p-2 border rounded">
<a
className="absolute p-1 space-x-1 text-xs bg-white right-2 -top-3"
href="https://ionic.io/ionicons"
target="_blank"
>
<span>View all icons</span>
<IonIcon icon={icons.openSharp} />
</a>
<IonGrid id="icons">
<IonRow>
{matchingIcons.length ? (
matchingIcons.map(([name, value]) => (
<IonCol
key={name}
size="1"
>
<IonIcon
className="cursor-pointer"
onClick={() => onClick({ name, value })}
icon={value}
></IonIcon>
</IonCol>
))
) : (
<p className="w-full m-2 text-center text-gray-300">
No matching icons
</p>
)}
</IonRow>
</IonGrid>
</div>
)
}

Expand Down
1 change: 1 addition & 0 deletions components/todos/TodoActionSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export function useTodoActionSheet() {
},
],
header: todo.title,
id: 'todo-action-sheet',
})
},
dismissActionSheet,
Expand Down
11 changes: 11 additions & 0 deletions cypress.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { defineConfig } from 'cypress'

export default defineConfig({
e2e: {
baseUrl: 'http://localhost:6603',
includeShadowDom: true,
setupNodeEvents(on, config) {
// implement node event listeners here
},
},
})
96 changes: 96 additions & 0 deletions cypress/e2e/spec.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
before(() => {
indexedDB.deleteDatabase('starfocus-zy0myinc2')
})

it('works', () => {
cy.visit('/home')

cy.get('#log').contains('Log').should('be.visible')
cy.get('#important').contains('Important').should('be.visible')
cy.get('#icebox').contains('Icebox').should('be.visible')

cy.get('ion-fab-button').click()
cy.get('ion-modal').within(() => {
cy.contains('label', 'Title')
.find('input')
.wait(2000)
.type('take the bins out')
cy.contains('Confirm').click()
})

cy.get('#view-menu-button').click()
cy.contains('ion-button', 'Edit roles')
// For some reason clicking edit roles doesn't work so we hard-navigate
cy.visit('/constellation')

cy.contains('ion-title', 'Constellation')

cy.get('ion-fab-button').click()
cy.get('ion-modal').within(() => {
cy.contains('label', 'Title').find('input').wait(2000).type('Father')
cy.get('#icons ion-icon').first().click()
cy.get('#selected-icon').should('have.attr', 'icon')
cy.wait(1000)
cy.contains('Confirm').click()
})

cy.get('ion-fab-button').click()
cy.get('ion-modal').within(() => {
cy.contains('label', 'Title').find('input').wait(2000).type('Partner')
cy.get('#icons ion-icon').eq(1).click()
cy.get('#selected-icon').should('have.attr', 'icon')
cy.wait(1000)
cy.contains('Confirm').click()
})

cy.visit('/home')

cy.get('ion-fab-button').click()
cy.get('ion-modal').within(() => {
cy.contains('label', 'Title')
.find('input')
.wait(2000)
.type('be silly together')
cy.get('ion-select[label="Star role"]').click()
})
cy.get('ion-alert').within(() => {
cy.contains('Father').click()
cy.contains('OK').click()
})
cy.get('ion-modal').contains('Confirm').click()

cy.get('ion-fab-button').click()
cy.get('ion-modal').within(() => {
cy.contains('label', 'Title')
.find('input')
.wait(2000)
.type('plan birthday day out')
cy.get('ion-select[label="Star role"]').click()
})
cy.get('ion-alert').within(() => {
cy.contains('Partner').click()
cy.contains('OK').click()
})
cy.get('ion-modal').contains('Confirm').click()

cy.get('#icebox').contains('take the bins out').click()
cy.get('#todo-action-sheet').contains('Move to important').click()
cy.get('#important').contains('take the bins out')

cy.wait(1000) // Why?
cy.get('#icebox').contains('be silly together').click()
cy.get('#todo-action-sheet').contains('Move to important').click()
cy.get('#important').contains('be silly together')

cy.wait(1000) // Why?
cy.get('#icebox').contains('plan birthday day out').click()
cy.get('#todo-action-sheet').contains('Move to important').click()
cy.get('#important').contains('plan birthday day out')

cy.wait(1000) // Why?
cy.get('#important')
.contains('.todo', 'take the bins out')
.find('ion-checkbox')
.click()
cy.get('#log').contains('take the bins out')
})
5 changes: 5 additions & 0 deletions cypress/fixtures/example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "Using fixtures to represent data",
"email": "[email protected]",
"body": "Fixtures are a great way to mock data for responses to routes"
}
Loading

0 comments on commit 5076df0

Please sign in to comment.