Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
054257e
Add Jest and testing script set up
RickV85 Apr 29, 2026
3ae58d5
add tsconfig
RickV85 Apr 29, 2026
cdf9ee6
Add simple forecast and gridpoint tests
RickV85 Apr 29, 2026
8251aa9
add hourly forecast tests
RickV85 Apr 29, 2026
ea50597
User tests
RickV85 May 2, 2026
c49a91f
utils tests
RickV85 May 2, 2026
fbe8e24
parsing tests
RickV85 May 2, 2026
48d8979
location and AI forecast tests
RickV85 May 2, 2026
257c6df
Update dependencies and enhance Cypress commands for stubbing API res…
RickV85 May 2, 2026
d899121
Add tests for adding a new location in the AddLocForm component, incl…
RickV85 May 2, 2026
6bda023
Refactor EditLocation tests to use stubAuthedFetches for API intercep…
RickV85 May 2, 2026
d03f48f
Refactor Home tests to utilize stub functions for API interception an…
RickV85 May 2, 2026
6659ce7
Refactor HomeAuthed tests to remove exclusive run flag and add new Ho…
RickV85 May 2, 2026
17b41d2
Add ESLint configuration for Cypress tests and update dependencies fo…
RickV85 May 2, 2026
09aebb4
Update HomeAuthed tests to use span for visibility check and enhance …
RickV85 May 2, 2026
fb3fa78
Add mobile viewport tests for home page and edit locations, including…
RickV85 May 2, 2026
e1f4864
Refactor forecast error handling tests to use stub functions for API …
RickV85 May 2, 2026
dc3db72
add package lock to gitignore
RickV85 May 9, 2026
660d9bc
update openai
RickV85 May 9, 2026
4cbd441
add retry
RickV85 May 11, 2026
31d687e
Refactor navigation button in tests and components to use consistent …
RickV85 May 19, 2026
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
7 changes: 7 additions & 0 deletions .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@
"plugin:@typescript-eslint/recommended",
"plugin:jsx-a11y/recommended"
],
"overrides": [
{
"extends": ["plugin:@cypress/dev/tests"],
"files": ["cypress/**/*.{js,jsx,ts,tsx}"],
"plugins": ["@cypress/dev", "mocha"]
}
],
"plugins": ["import"],
"rules": {
"@typescript-eslint/no-explicit-any": "error",
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ jobs:
path: |
~/.npm
${{ github.workspace }}/.next/cache
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }}
key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package.json') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }}
restore-keys: |
${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}
${{ runner.os }}-nextjs-${{ hashFiles('**/package.json') }}

- name: Install dependencies
run: npm ci
run: npm install

- name: Lint
run: npm run lint
Expand Down Expand Up @@ -49,12 +49,12 @@ jobs:
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
key: ${{ runner.os }}-npm-${{ hashFiles('**/package.json') }}
restore-keys: |
${{ runner.os }}-npm-

- name: Install dependencies
run: npm ci
run: npm install

- name: Build Next.js app
env:
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
/node_modules
.pnp.js
.yarn/install-state.gz
package-lock.json

# testing
/coverage
Expand Down
10 changes: 5 additions & 5 deletions cypress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import { defineConfig } from 'cypress';

export default defineConfig({
projectId: '361teg',
retries: {
runMode: 3,
openMode: 0,
},
e2e: {
setupNodeEvents(on, config) {
setupNodeEvents() {
// implement node event listeners here
},
retries: {
runMode: 2,
openMode: 0,
},
baseUrl: 'http://localhost:3000',
},
});
117 changes: 117 additions & 0 deletions cypress/e2e/AddLocForm.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
describe('AddLocForm happy path', () => {
beforeEach(() => {
cy.stubAuthedFetches();

Cypress.on('uncaught:exception', () => {
return false;
});

cy.intercept('POST', '/api/user_locations', {
body: JSON.stringify('Success: New user location created for user_id: 101000928729222042760'),
statusCode: 201,
}).as('postUserLocation');

cy.visit('/edit-locations');
cy.injectAxe();
});

it('should display the add location section with map instructions', () => {
cy.get('h2#addLocTitle').should('have.text', 'Add New Location');
cy.get('section.add-loc-section')
.find('p')
.should(
'have.text',
'Scroll down to view entire map below, then click on the map where you would like to create a new location.',
);
});

it('should show the add location form after clicking the map and submit successfully', () => {
cy.waitForAddLocationGoogleMapReady();

cy.get('div.map-container [role="application"]').click(200, 200);

cy.get('form.add-loc-form', { timeout: 10000 }).should('be.visible');

cy.get('#addLocNameInput').type('Test Location');
cy.get('select[aria-label="Select location type for your new custom location"]').select(
'Climbing',
);

cy.get('form.add-loc-form').contains('button', 'Save').click();

cy.wait('@postUserLocation');
cy.get('#submitMessage').should('have.text', 'New location saved!');
});

it('should show validation error when name is empty', () => {
cy.waitForAddLocationGoogleMapReady();

cy.get('div.map-container [role="application"]').click(200, 200);

cy.get('form.add-loc-form', { timeout: 10000 }).should('be.visible');

cy.get('select[aria-label="Select location type for your new custom location"]').select(
'Climbing',
);
cy.get('form.add-loc-form').contains('button', 'Save').click();

cy.get('#submitMessage').should('have.text', 'Please enter a name for your new location.');
});

it('should show validation error when name exceeds 50 characters', () => {
cy.waitForAddLocationGoogleMapReady();

cy.get('div.map-container [role="application"]').click(200, 200);

cy.get('form.add-loc-form', { timeout: 10000 }).should('be.visible');

cy.get('#addLocNameInput').type(
'This name is way too long and exceeds the fifty character limit easily',
);
cy.get('select[aria-label="Select location type for your new custom location"]').select(
'Climbing',
);
cy.get('form.add-loc-form').contains('button', 'Save').click();

cy.get('#submitMessage').should(
'have.text',
'Location names cannot be longer than 50 characters.',
);
});

it('should show validation error when no type is selected', () => {
cy.waitForAddLocationGoogleMapReady();

cy.get('div.map-container [role="application"]').click(200, 200);

cy.get('form.add-loc-form', { timeout: 10000 }).should('be.visible');

cy.get('#addLocNameInput').type('Test Location');
cy.get('form.add-loc-form').contains('button', 'Save').click();

cy.get('#submitMessage').should('have.text', 'Please select a type for this location.');
});

it('should cancel and remove form when Cancel is clicked', () => {
cy.waitForAddLocationGoogleMapReady();

cy.get('div.map-container [role="application"]').click(200, 200);

cy.get('form.add-loc-form', { timeout: 10000 }).should('be.visible');

cy.get('form.add-loc-form').contains('button', 'Cancel').click();

cy.get('form.add-loc-form').should('not.exist');
cy.get('section.add-loc-section')
.find('p')
.should(
'have.text',
'Scroll down to view entire map below, then click on the map where you would like to create a new location.',
);
});

it('should have no accessibility violations', () => {
cy.get('h2#addLocTitle').should('be.visible');
cy.checkA11y();
});
});
70 changes: 25 additions & 45 deletions cypress/e2e/EditLocationDisplay.cy.ts
Original file line number Diff line number Diff line change
@@ -1,51 +1,31 @@
describe('Edit locations display', () => {
beforeEach(() => {
// Intercept and return user session object
cy.intercept('/api/auth/session', {
fixture: 'session.json',
});

// Intercept user login patch req
cy.intercept(
'/api/users',
JSON.stringify(
'New user data for id: 101000928729222042760 matches previous user data from database. New login: 2024-02-25T17:35:44.233Z',
),
);

// Intercept user location req
cy.intercept('/api/user_locations?user_id=101000928729222042760', {
fixture: 'user_locs.json',
});

// Intercept default locations req
cy.intercept('/api/default_locations', {
fixture: 'default_locs.json',
});
cy.stubAuthedFetches();

// Ignore Google maps 3d context error when run in GH Actions
Cypress.on('uncaught:exception', (err, runnable) => {
Cypress.on('uncaught:exception', () => {
return false;
});

cy.visit('/');
cy.injectAxe();

cy.get('button#navLocationBtn').click();
cy.get('#navLocationBtn').click();
cy.location('pathname').should('equal', '/edit-locations');
});

cy.wait(250);
it('should have no accessibility violations', () => {
cy.get('h2').eq(0).should('have.text', 'Edit Custom Locations');
cy.checkA11y();
});

it("should display the site title, 'SendTemps' and return user to Home when clicked", () => {
cy.wait(500);
cy.get('h1').should('have.text', 'SendTemps').click();

cy.wait(1000).location('pathname').should('equal', '/');
cy.location('pathname').should('equal', '/');
});

it('should display the Back button and allow user to return to Home', () => {
cy.get('button#editLocBackBtn').should('be.visible').should('have.text', 'Back').click();

cy.wait(250).location('pathname').should('equal', '/');
cy.location('pathname').should('equal', '/');
});

it('should show the heading for the edit location section', () => {
Expand All @@ -55,7 +35,6 @@ describe('Edit locations display', () => {
it('should display a select to pick a custom location to edit', () => {
cy.get('select#editUserLocSelect').as('editLocSelect').should('be.visible');
cy.get('@editLocSelect').find('option').eq(0).should('have.text', 'Choose location');

cy.get('@editLocSelect').find('option').eq(1).should('have.text', 'Eldora');
});

Expand All @@ -75,12 +54,11 @@ describe('Edit locations display', () => {
JSON.stringify(
'Success: User Location id: 34 for user_id: 101000928729222042760 successfully deleted',
),
);
).as('deleteUserLocation');

cy.get('button#userLocDeleteBtn').as('deleteBtn').should('be.visible');

cy.get('@deleteBtn').click();
// Tests for no location selected, not needed on next two tests of CRUD functions
cy.get('dialog#userLocModal')
.as('locModal')
.contains('Please select a location before editing.');
Expand All @@ -95,22 +73,23 @@ describe('Edit locations display', () => {
cy.get('@deleteBtn').click();
cy.get('@locModal').find('button').eq(1).should('have.text', 'Confirm').click();

cy.wait('@deleteUserLocation');
cy.get('select#editUserLocSelect').should('not.exist');
});

it('should show the Rename button, open modal, allow return, and rename', () => {
cy.intercept('PATCH', '/api/user_locations', {
patchLoc: {
date_created: '2024-03-06T21:42:17.348Z',
id: 34,
name: 'Renamed',
last_modified: '2024-03-07T14:50:42.158Z',
latitude: '40.041410',
longitude: '-105.089064',
user_id: '101000928729222042760',
name: 'Renamed',
poi_type: 'ski',
date_created: '2024-03-06T21:42:17.348Z',
last_modified: '2024-03-07T14:50:42.158Z',
user_id: '101000928729222042760',
},
});
}).as('patchUserLocation');

cy.get('button#userLocRenameBtn').as('renameBtn').should('be.visible');

Expand All @@ -127,22 +106,23 @@ describe('Edit locations display', () => {
cy.get('input#editUserLocNameInput').type('Renamed');
cy.get('@locModal').find('button').eq(1).should('have.text', 'Confirm').click();

cy.wait('@patchUserLocation');
cy.get('select#editUserLocSelect').find('option').eq(1).should('have.text', 'Renamed');
});

it('should show the Change Type button, open modal, allow return, and change type', () => {
cy.intercept('PATCH', '/api/user_locations', {
patchLoc: {
date_created: '2024-03-06T21:42:17.348Z',
id: 34,
name: 'Eldora',
last_modified: '2024-03-07T14:50:42.158Z',
latitude: '40.041410',
longitude: '-105.089064',
user_id: '101000928729222042760',
name: 'Eldora',
poi_type: 'mtb',
date_created: '2024-03-06T21:42:17.348Z',
last_modified: '2024-03-07T14:50:42.158Z',
user_id: '101000928729222042760',
},
});
}).as('patchUserLocation');

cy.get('button#userLocTypeBtn').as('typeBtn').should('be.visible');

Expand All @@ -159,8 +139,8 @@ describe('Edit locations display', () => {
cy.get('select.edit-loc-input').select('Mountain Biking');
cy.get('@locModal').find('button').eq(1).should('have.text', 'Confirm').click();

cy.wait('@patchUserLocation');
cy.get('select#editUserLocSelect').select('Eldora');

cy.get('dl').find('div').eq(2).find('dd').should('have.text', 'Mountain Biking');
});

Expand Down
Loading
Loading