Skip to content

Commit

Permalink
feat: Apps query client connection and save calculation action (#82)
Browse files Browse the repository at this point in the history
* feat: connect to graasp-app-api

* feat: save calc action on equality

* fix: setup api for cypress tests to add appcontext and databse

* fix: use sdk factories for member and item

* fix: add default values for setupApi cy command for db and app context
  • Loading branch information
LinaYahya authored Feb 27, 2024
1 parent 1d4ac67 commit 9490126
Show file tree
Hide file tree
Showing 15 changed files with 386 additions and 20 deletions.
1 change: 1 addition & 0 deletions cypress/e2e/Calculator.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ describe('Calculator', () => {

describe('scientific mode = false', () => {
before(() => {
cy.setUpApi();
cy.visitAsStudent({ appQueryParameters });
});

Expand Down
1 change: 1 addition & 0 deletions cypress/e2e/Keyboard.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ describe('Keyboard', () => {
const resultErrorSelector = `[data-cy="${RESULT_TEXT_NAME}"] .katex-error`;

before(() => {
cy.setUpApi();
cy.visitAsStudent({ appQueryParameters });
});

Expand Down
11 changes: 11 additions & 0 deletions cypress/fixtures/members.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Member, MemberFactory } from '@graasp/sdk';

const ANNA = MemberFactory({ name: 'anna', email: '[email protected]' });
const BOB = MemberFactory({ name: 'bob', email: '[email protected]' });

export const MEMBERS: { [key: string]: Member } = {
ANNA,
BOB,
};

export const CURRENT_MEMBER = MEMBERS.ANNA;
7 changes: 7 additions & 0 deletions cypress/fixtures/mockItem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { AppItemFactory } from '@graasp/sdk';
import { MEMBERS } from './members';

export const MOCK_APP_ITEM = AppItemFactory({
name: 'calc1',
creator: MEMBERS.ANNA,
});
24 changes: 24 additions & 0 deletions cypress/support/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,30 @@ import {
SCIENTIFIC_MODE_SWITCH_NAME,
} from '../../src/config/selectors';
import { LOAD_PAGE_PAUSE, CLICK_BUTTON_PAUSE } from '../constants';
import { CURRENT_MEMBER, MEMBERS } from '../fixtures/members';
import { MOCK_APP_ITEM } from '../fixtures/mockItem';

Cypress.Commands.add('setUpApi', (database = {}, appContext = {}) => {
Cypress.on('window:before:load', (win: Window) => {
win.indexedDB.deleteDatabase('graasp-app-cypress');
// eslint-disable-next-line no-param-reassign
win.appContext = {
memberId: CURRENT_MEMBER.id,
itemId: MOCK_APP_ITEM.id,
apiHost: Cypress.env('VITE_API_HOST'),
...appContext,
};
// eslint-disable-next-line no-param-reassign
win.database = {
appData: [],
appActions: [],
appSettings: [],
members: Object.values(MEMBERS),
items: [MOCK_APP_ITEM],
...database,
};
});
});

Cypress.Commands.add(
'visitAsStudent',
Expand Down
6 changes: 6 additions & 0 deletions cypress/support/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// cypress/support/index.ts

import { Database, LocalContext } from '@graasp/apps-query-client';
import { ANGLE_UNITS } from 'config/constants';
import { ValueOf } from 'types/math';

Expand All @@ -10,6 +11,11 @@ declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace Cypress {
interface Chainable {
setUpApi(
database?: Partial<Database>,
appContext?: Partial<LocalContext>,
): void;

visitAsStudent(
args: { appQueryParameters: AppQueryParameters },
scientificMode?: boolean,
Expand Down
11 changes: 11 additions & 0 deletions cypress/window.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
declare global {
interface Window {
appContext: LocalContext;
Cypress: boolean;
database: Database;
apiErrors: object;
katex: katex;
}
}

export {};
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@
"@emotion/react": "11.11.1",
"@emotion/styled": "11.11.0",
"@graasp/apps-query-client": "3.4.1",
"@graasp/sdk": "3.10.0",
"@graasp/ui": "3.0.0",
"@mui/icons-material": "5.14.3",
"@mui/lab": "5.0.0-alpha.134",
"@mui/material": "5.14.4",
"@tanstack/react-query": "4.36.1",
"@tanstack/react-query-devtools": "4.36.1",
"i18next": "22.5.1",
"katex": "0.16.7",
"lodash.isnan": "3.0.2",
Expand Down Expand Up @@ -52,7 +55,7 @@
"test": "yarn build:test && concurrently -k -s first \"yarn preview:test\" \"yarn cypress:run\"",
"cypress:run": "env-cmd -f ./.env.test cypress run --browser chrome",
"report": "cat ./coverage/lcov.info | codacy-coverage",
"cypress:open": "cypress open",
"cypress:open": "env-cmd -f ./.env.test cypress open",
"cypress": "npm-run-all --parallel start cypress:open",
"postinstall": "husky install"
},
Expand Down
57 changes: 48 additions & 9 deletions src/components/Root.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,57 @@
import { I18nextProvider } from 'react-i18next';
import { ThemeProvider } from '@mui/material/styles';
import { ToastContainer } from 'react-toastify';
import { theme } from '@graasp/ui';
import { Loader, theme } from '@graasp/ui';
import 'react-toastify/dist/ReactToastify.css';
import {
GraaspContextDevTool,
WithLocalContext,
WithTokenContext,
useObjectState,
} from '@graasp/apps-query-client';
import { QueryClientProvider, hooks, queryClient } from '@/config/queryClient';
import { defaultMockContext, mockMembers } from '@/mocks/db';
import i18nConfig from '../config/i18n';
import App from './App';

const Root = (): JSX.Element => (
<ThemeProvider theme={theme}>
<I18nextProvider i18n={i18nConfig}>
<App />
<ToastContainer />
</I18nextProvider>
</ThemeProvider>
);
const Root = (): JSX.Element => {
const [mockContext, setMockContext] = useObjectState(defaultMockContext);

return (
<ThemeProvider theme={theme}>
<I18nextProvider i18n={i18nConfig}>
<QueryClientProvider client={queryClient}>
<ToastContainer />
<WithLocalContext
defaultValue={window.Cypress ? window.appContext : mockContext}
LoadingComponent={<Loader />}
useGetLocalContext={hooks.useGetLocalContext}
useAutoResize={hooks.useAutoResize}
onError={(e) => {
console.error('An error occurred while fetching the context.', e);
}}
>
<WithTokenContext
LoadingComponent={<Loader />}
useAuthToken={hooks.useAuthToken}
onError={() => {
console.error('An error occurred while requesting the token.');
}}
>
<App />
{import.meta.env.DEV && (
<GraaspContextDevTool
members={mockMembers}
context={mockContext}
setContext={setMockContext}
/>
)}
</WithTokenContext>
</WithLocalContext>
</QueryClientProvider>
</I18nextProvider>
</ThemeProvider>
);
};

export default Root;
31 changes: 22 additions & 9 deletions src/components/common/Calculator.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
import { useState, useEffect, useCallback } from 'react';
import * as math from 'mathjs';
import isNaN from 'lodash.isnan';

import Grid from '@mui/material/Grid';
import { useTranslation } from 'react-i18next';
import { Box } from '@mui/material';
import FocusIndicator from '../FocusIndicator';
import ScientificSwitch from '../ScientificSwitch';
import Result from './Result';
import KeyPad from './Keypad';
import { RESULT_ERROR_MESSAGE } from '../../config/messages';
import {
KEYPAD_BUTTONS,
BUTTON_NAMES,
Expand All @@ -19,7 +13,14 @@ import {
SCIENTIFIC_CALCULATOR_MAX_WIDTH,
ANGLE_UNITS,
OPERATIONS,
} from '../../config/constants';
CalculationTriggers,
} from '@/config/constants';
import { mutations } from '@/config/queryClient';
import FocusIndicator from '../FocusIndicator';
import ScientificSwitch from '../ScientificSwitch';
import Result from './Result';
import KeyPad from './Keypad';
import { RESULT_ERROR_MESSAGE } from '../../config/messages';
import AngleUnitSwitch from './AngleUnitSwitch';
import {
backSpace,
Expand Down Expand Up @@ -49,6 +50,14 @@ const Calculator = ({ standalone = false }: Props): JSX.Element => {
const [scientificMode, setScientificMode] = useState(false);
const [history, setHistory] = useState<string[]>([]);

const { mutate: postAction } = mutations.usePostAppAction();

const saveAction = (data: { equation: string; result: string }): void => {
postAction({
data,
type: CalculationTriggers.EQUATION,
});
};
const updateResult = useCallback(
({
name,
Expand Down Expand Up @@ -168,7 +177,10 @@ const Calculator = ({ standalone = false }: Props): JSX.Element => {
newHistory.push(name);
break;
}

// to trigger action on equality operation
if (name === BUTTON_NAMES.EQUAL) {
saveAction({ equation: mathjs, result: newResult });
}
setResult(newResult);
setMathjs(newMathjs);
setHistory(newHistory);
Expand All @@ -179,7 +191,8 @@ const Calculator = ({ standalone = false }: Props): JSX.Element => {
setHistory([]);
}
},
[history, mathjs, result, t],
// eslint-disable-next-line react-hooks/exhaustive-deps
[history, mathjs, result],
);

const handleKeydown = useCallback(
Expand Down
4 changes: 4 additions & 0 deletions src/config/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,3 +184,7 @@ export const TRIGONOMETRY_SPECIAL_CASES: SpecialCases = {

export const ROUND_OFF_ERROR_MARGIN = 1.58;
export const BUTTON_FONT_SIZE = '1.9rem';

export enum CalculationTriggers {
EQUATION = 'calculation-equation',
}
29 changes: 29 additions & 0 deletions src/config/queryClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { configureQueryClient } from '@graasp/apps-query-client';

import { API_HOST, GRAASP_APP_KEY, MOCK_API } from './env';

const {
queryClient,
QueryClientProvider,
hooks,
API_ROUTES,
mutations,
ReactQueryDevtools,
} = configureQueryClient({
API_HOST,
refetchOnWindowFocus: !import.meta.env.DEV,
keepPreviousData: true,
// avoid refetching when same data are closely fetched
staleTime: 1000, // ms
GRAASP_APP_KEY,
isStandalone: MOCK_API,
});

export {
ReactQueryDevtools,
queryClient,
QueryClientProvider,
hooks,
mutations,
API_ROUTES,
};
25 changes: 24 additions & 1 deletion src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,30 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import Root from './components/Root';
import './index.css';
import {
mockApi,
buildDatabase,
MockSolution,
} from '@graasp/apps-query-client';
import Root from './components/Root';
import { MOCK_API } from './config/env';
import { defaultMockContext, mockMembers } from './mocks/db';

// setup mocked api for cypress or standalone app
/* istanbul ignore next */
if (MOCK_API) {
mockApi(
{
externalUrls: [],
dbName: window.Cypress ? 'graasp-app-cypress' : undefined,
appContext: window.Cypress ? window.appContext : defaultMockContext,
database: window.Cypress
? window.database
: buildDatabase({ members: mockMembers }),
},
window.Cypress ? MockSolution.MirageJS : MockSolution.ServiceWorker,
);
}

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<Root />,
Expand Down
Loading

0 comments on commit 9490126

Please sign in to comment.