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

Handle geolocation error, handle timezone error, add tests #4

Merged
merged 3 commits into from
Feb 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 3 additions & 0 deletions playwright.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ const config = {
command: 'npm run build && npm run preview',
port: 4173
},
use: {
permissions: ['geolocation']
},
testDir: 'tests',
testMatch: /(.+\.)?(test|spec)\.[jt]s/
};
Expand Down
9 changes: 7 additions & 2 deletions src/lib/components/PreComponents/FormLocate.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,11 @@
console.log(position.coords);
$preFormInput.latlon = `${position.coords.latitude},${position.coords.longitude}`;
};
await navigator.geolocation.getCurrentPosition(success, error, options);
try {
await navigator.geolocation.getCurrentPosition(success, error, options);
} catch (error) {
console.error(error);
}
};
</script>

Expand Down Expand Up @@ -81,7 +85,8 @@
</button>
{#if locateError.error}
<span class="locate-error">
{#if locateError.code === 1}{$_('pre_submit.locate_error')} {/if}({locateError.message})
{#if locateError.code === 1}{$_('pre_submit.locate_error')}
{/if}({locateError.message})
</span>
{/if}

Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/PreComponents/PreInputForm.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
if (result.type === 'failure') {
// render error text
if (
result.data.type === 'Timezone Offset Error' ||
result.data.type === 'timezoneOffsetError' ||
result.data.type === 'GetWeatherForStartAndEnd error'
) {
$preErrorText = result.data.message;
Expand Down
23 changes: 23 additions & 0 deletions src/lib/services/timezone.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { test, expect } from 'vitest';
import { find } from 'geo-tz';

test('Timezone is able to be found with some edge case GPS coordinates', () => {
// threw error in RainCrow with geo-tz 8.0.1
expect(find(41.796014, -87.576506)).toStrictEqual(['America/Chicago']);
// threw error in RainCrow with geo-tz 8.0.1
expect(find(24.597694, -81.583389)).toStrictEqual(['America/New_York']);
// threw error in RainCrow with geo-tz 8.0.1
expect(find(24.566016, -81.673234)).toStrictEqual(['America/New_York']);
// gave problems on github issue apparently
expect(find(-24.244125928804735, -53.8226425697034)).toStrictEqual(['America/Sao_Paulo']);
// gave problems on github issue apparently
expect(find(34.05861, -118.3928)).toStrictEqual(['America/Los_Angeles']);
// Edge of Reservation Land in NE AZ (Rez)
expect(find(35.1578900375291, -111.24227457293293)).toStrictEqual(['America/Denver']);
// Edge of Reservation Land in NE AZ (Non-rez)
expect(find(35.15698602683568, -111.24796115826194)).toStrictEqual(['America/Phoenix']);
// Middle of the Atlantic Ocean
expect(find(43.298646833300026, -38.425597455498185)).toStrictEqual(['Etc/GMT+3']);
// CA/AZ border
expect(find(33.608429524254916, -114.53309086102836)).toStrictEqual(['America/Los_Angeles']);
});
11 changes: 10 additions & 1 deletion src/lib/services/validation.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import { parseLatlon } from './parseLatlon';

export const validateLatlon = (latlon) => {
const latlonRegex = /\s*-?\d+\.\d+,\s*-?\d+\.\d+\s*/;
return latlon.match(latlonRegex) ? true : false;
const textFormatCheck = latlon.match(latlonRegex) ? true : false;
const { lat, lon } = parseLatlon(latlon);
const latNum = parseInt(lat);
const lonNum = parseInt(lon);
const latNumCheck = latNum >= -90 && latNum <= 90;
const lonNumCheck = lonNum >= -180 && lonNum <= 180;

return textFormatCheck && latNumCheck && lonNumCheck;
};

export const validateDate = (date) => {
Expand Down
15 changes: 15 additions & 0 deletions src/lib/services/validation.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { describe, expect, test } from 'vitest';
import { validateLatlon } from './validation';

describe('Validate Lat Lon', () => {
test('validates valid lat lon', () => {
expect(validateLatlon('33.33, -22.22')).toBe(true);
expect(validateLatlon('33.0, -82.2')).toBe(true);
});
test('Rejects invalid latlon', () => {
expect(validateLatlon('-91.00, 111.11')).toBe(false);
expect(validateLatlon('91.00, 111.11')).toBe(false);
expect(validateLatlon('44.4, -181.0')).toBe(false);
expect(validateLatlon('44.4, 181.0')).toBe(false);
});
});
12 changes: 9 additions & 3 deletions src/routes/postGetWeather.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,19 @@ export default async function postGetWeather({ fetch, request, cookies }) {
console.log('dayjsTimes', dayjsTimes);

// ---- Get unixtime from timezone ----
const tz = find(postWeather.location.lat, postWeather.location.lon);
console.log('timezone', tz);
let tz;
try {
tz = find(postWeather.location.lat, postWeather.location.lon);
} catch (error) {
return fail(400, {
type: 'timezoneOffsetError',
message: 'Error getting time zone for checklist coordinates'
});
}
dayjsTimes.start.unixTime = dayjsTimes.start.localTime.tz(tz, true).unix();
if (dayjsTimes.end.localTime) {
dayjsTimes.end.unixTime = dayjsTimes.end.localTime.tz(tz, true).unix();
}
console.log('unixTimes included', dayjsTimes);

// ---- Query weather ----
postWeather.weatherResults = await getWeatherForStartAndEnd(postWeather, dayjsTimes, fetch);
Expand Down
11 changes: 10 additions & 1 deletion src/routes/preGetWeather.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,16 @@ export default async function preGetWeather({ fetch, request, cookies }) {
dayjsTimes.end.localTime = dayjs(dayjsTimes.start.localTime).add(duration, 'minute');

// ---- Get unixtime from timezone ----
const tz = find(preWeather.location.lat, preWeather.location.lon);
let tz;
try {
tz = find(preWeather.location.lat, preWeather.location.lon);
} catch (error) {
return fail(400, {
...errorObj,
type: 'timezoneOffsetError',
message: 'Error getting time zone for given coordinates'
});
}
dayjsTimes.start.unixTime = dayjsTimes.start.localTime.tz(tz, true).unix();
if (dayjsTimes.end.localTime) {
dayjsTimes.end.unixTime = dayjsTimes.end.localTime.tz(tz, true).unix();
Expand Down
22 changes: 22 additions & 0 deletions tests/geolocation.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { expect, test } from '@playwright/test';

test('Error is displayed when user denies geolocation', async ({ page }) => {
await page.goto('/');
await page.getByRole('button', { name: 'Pre-Submit' }).click();
await page.getByRole('button', { name: 'Locate' }).click();
await expect(page.getByText('Allow location access to use')).toBeVisible();
});

test.describe('When Geolocation is granted', () => {
test.use({
geolocation: { longitude: 41.890221, latitude: 12.492348 },
permissions: ['geolocation']
});

test('Locate button works and fills out the input', async ({ page }) => {
await page.goto('/');
await page.getByRole('button', { name: 'Pre-Submit' }).click();
await page.getByRole('button', { name: 'Locate' }).click();
await expect(page.getByLabel('Location (Latitude, Longitude)')).not.toBeEmpty();
});
});
27 changes: 0 additions & 27 deletions tests/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,30 +10,3 @@ test('index page has nav bar', async ({ page }) => {
await expect(page.getByRole('button', { name: 'Submitted' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Pre-Submit' })).toBeVisible();
});

test.beforeEach(async ({ context }) => {
await context.route('https://api.ebird.org/v2/**', async (route) => {
const json = {
message: { checklist: ['info'] }
};
await route.fulfill({ json });
});
await context.route(
'https://api.openweathermap.org/data/3.0/onecall/timemachine**',
async (route) => {
const json = {
weather: { results: 'hot' }
};
await route.fulfill({ json });
}
);
});

test('makes mock API request', async ({ page }) => {
await page.goto('/');
await page.getByRole('button', { name: 'Submitted' }).click();
await page.getByLabel('Checklist ID:').click();
await page.getByLabel('Checklist ID:').fill('https://ebird.org/checklist/S142104802');
await page.getByRole('button', { name: 'Get Weather' }).click();
await expect(page.getByTestId('weatherResultsPane').toContainText('fail'));
});
Loading