-
Notifications
You must be signed in to change notification settings - Fork 7
feat(sync): RN-1545: Fix bugs #6492
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
Changes from 36 commits
4cb810e
486c294
7b161c0
2fa2bc4
f233006
bdab5cf
c2fa961
1f01d5f
4558f04
22cb462
fb13d03
d862469
ad87c49
8cbd16e
66358a4
450230a
69fb2f9
3b82aea
a3c4ebf
48c5859
59f92b4
8971226
34875ca
c3cf790
872a75e
6eac371
46f4730
503ed8e
85b4bb3
2615578
806fd1c
73159a3
9d83e78
2f714d9
a3b392f
c7dc6af
1f6763a
50c8e2c
8648fbf
3aa3cd0
d8601d4
e9c040f
9f48e0d
42f8597
78aeadb
a7ac4c9
759be74
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -336,6 +336,10 @@ export class EntityRecord extends DatabaseRecord { | |
| export class EntityModel extends MaterializedViewLogDatabaseModel { | ||
| static syncDirection = SyncDirections.BIDIRECTIONAL; | ||
|
|
||
| get ExcludedFieldsFromSync() { | ||
| return ['point', 'bounds', 'region', 'parent_id']; | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| get DatabaseRecordClass() { | ||
| return EntityRecord; | ||
| } | ||
|
|
@@ -699,9 +703,4 @@ export class EntityModel extends MaterializedViewLogDatabaseModel { | |
| groupBy: ['entity.id'], | ||
| }; | ||
| } | ||
|
|
||
| sanitizeForClient = data => { | ||
| const { point, bounds, region, parent_id, ...sanitizedData } = data; | ||
| return sanitizedData; | ||
| }; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,92 @@ | ||
| // TODO: Set up database for testing later | ||
| /** | ||
| * This is the Jest-sanctioned workaround | ||
| * @see https://jestjs.io/docs/manual-mocks#mocking-methods-which-are-not-implemented-in-jsdom | ||
| */ | ||
| Object.defineProperty(window, 'matchMedia', { | ||
|
Comment on lines
1
to
5
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice, centralising this is much cleaner 🙏 |
||
| writable: true, | ||
| value: jest.fn().mockImplementation(query => ({ | ||
| matches: false, | ||
| media: query, | ||
| onchange: null, | ||
| addListener: jest.fn(), // deprecated | ||
| removeListener: jest.fn(), // deprecated | ||
| addEventListener: jest.fn(), | ||
| removeEventListener: jest.fn(), | ||
| dispatchEvent: jest.fn(), | ||
| })), | ||
| }); | ||
|
|
||
| const mockModels = { | ||
| localSystemFact: { | ||
| get: jest.fn().mockResolvedValue('test-device-id'), | ||
| set: jest.fn().mockResolvedValue(undefined), | ||
| addProjectForSync: jest.fn(), | ||
| }, | ||
| closeDatabaseConnections: jest.fn(), | ||
| }; | ||
|
|
||
| jest.mock('@tupaia/database', () => ({ | ||
| migrate: jest.fn(), | ||
| ModelRegistry: jest.fn().mockImplementation(() => ({})), | ||
| })); | ||
|
|
||
| jest.mock('./src/database/DatatrakDatabase', () => ({ | ||
| DatatrakDatabase: jest.fn().mockImplementation(() => ({})), | ||
| jest.mock('./src/database/createDatabase', () => ({ | ||
| createDatabase: jest.fn().mockImplementation(() => ({ | ||
| models: { | ||
| localSystemFact: { | ||
| get: jest.fn().mockImplementation(arg => { | ||
| if (arg === 'deviceId') { | ||
| return 'test-device-id'; | ||
| } | ||
| return undefined; | ||
| }), | ||
| addProjectForSync: jest.fn(), | ||
| }, | ||
| }, | ||
| })), | ||
| })); | ||
|
|
||
| jest.mock('./src/api/CurrentUserContext', () => { | ||
| const actual = jest.requireActual('./src/api/CurrentUserContext'); | ||
|
|
||
| return { | ||
| ...actual, | ||
| useCurrentUserContext: jest.fn(() => ({ | ||
| ...actual.useCurrentUserContext(), // Get the actual return value | ||
| accessPolicy: {}, // Override just this property | ||
| })), | ||
| }; | ||
| }); | ||
|
|
||
| // TODO: Set up database for testing later | ||
| jest.mock('./src/api/DatabaseContext', () => { | ||
| const React = require('react'); | ||
|
|
||
| return { | ||
| DatabaseContext: React.createContext({ | ||
| models: mockModels, | ||
| }), | ||
| DatabaseProvider: ({ children }) => children, | ||
| useDatabaseContext: () => ({ | ||
| models: mockModels, | ||
| }), | ||
| }; | ||
| }); | ||
|
|
||
| jest.mock('./src/api/SyncContext', () => { | ||
| const React = require('react'); | ||
|
|
||
| return { | ||
| SyncContext: React.createContext({ | ||
| clientSyncManager: { | ||
| triggerSync: jest.fn(), | ||
| }, | ||
| }), | ||
| SyncProvider: ({ children }) => children, | ||
| useSyncContext: () => ({ | ||
| clientSyncManager: { | ||
| triggerSync: jest.fn(), | ||
| }, | ||
| }), | ||
| }; | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -40,7 +40,7 @@ describe('Login', () => { | |
| renderPage('/login'); | ||
| expect(await screen.findByRole('heading', { level: 2 })).toHaveTextContent('Log in'); | ||
| await doLogin(); | ||
| server.use(mockUserRequest({ email: '[email protected]' })); | ||
| server.use(mockUserRequest({ email: '[email protected]', accessPolicy: [] })); | ||
|
|
||
| expect(await screen.findByRole('heading', { level: 1 })).toHaveTextContent(/Select project/i); | ||
| }); | ||
|
|
@@ -49,7 +49,7 @@ describe('Login', () => { | |
| renderPage('/login'); | ||
| expect(await screen.findByRole('heading', { level: 2 })).toHaveTextContent('Log in'); | ||
|
|
||
| server.use(mockUserRequest({ email: '[email protected]', projectId: 'foo' })); | ||
| server.use(mockUserRequest({ email: '[email protected]', projectId: 'foo', accessPolicy: [] })); | ||
| await doLogin(); | ||
|
|
||
| await screen.findByText(/Select survey/i); | ||
|
|
@@ -59,7 +59,7 @@ describe('Login', () => { | |
| renderPage('/survey'); | ||
| expect(await screen.findByRole('heading', { level: 2 })).toHaveTextContent('Log in'); | ||
|
|
||
| server.use(mockUserRequest({ email: '[email protected]', projectId: 'foo' })); | ||
| server.use(mockUserRequest({ email: '[email protected]', projectId: 'foo', accessPolicy: [] })); | ||
| await doLogin(); | ||
|
|
||
| expect(await screen.findByRole('heading', { level: 1 })).toHaveTextContent(/Select survey/i); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,7 +9,14 @@ import { handlers } from '../mocks/handlers'; | |
| const server = setupServer( | ||
| ...handlers, | ||
| rest.get('*/v1/getUser', (_, res, ctx) => { | ||
| return res(ctx.status(200), ctx.json({ name: 'John Smith', email: '[email protected]' })); | ||
| return res( | ||
| ctx.status(200), | ||
| ctx.json({ | ||
| name: 'John Smith', | ||
| email: '[email protected]', | ||
| id: '0'.repeat(24), | ||
| }), | ||
| ); | ||
| }), | ||
| rest.get('*/v1/*', (_, res, ctx) => { | ||
| return res(ctx.status(200), ctx.json([])); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,7 +9,10 @@ import { handlers } from '../../mocks/handlers'; | |
| const server = setupServer( | ||
| ...handlers, | ||
| rest.get('*/v1/getUser', (_, res, ctx) => { | ||
| return res(ctx.status(200), ctx.json({ name: 'John Smith', email: '[email protected]' })); | ||
| return res( | ||
| ctx.status(200), | ||
| ctx.json({ name: 'John Smith', email: '[email protected]', id: '0'.repeat(24) }), | ||
| ); | ||
| }), | ||
| ); | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,7 +3,6 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; | |
| import { useDatabaseContext } from '../../hooks/database'; | ||
| import { UserAccountDetails } from '../../types'; | ||
| import { put } from '../api'; | ||
| import { useSyncContext } from '../SyncContext'; | ||
|
|
||
| /** | ||
| * Converts a string from camel case to snake case. | ||
|
|
@@ -22,7 +21,6 @@ function camelToSnakeCase(camelCaseString: string): string { | |
| export const useEditUser = (onSuccess?: () => void) => { | ||
| const queryClient = useQueryClient(); | ||
| const { models } = useDatabaseContext(); | ||
| const { refetchSyncedProjectIds } = useSyncContext(); | ||
|
|
||
| return useMutation<any, Error, UserAccountDetails, unknown>( | ||
| async (userDetails: UserAccountDetails) => { | ||
|
|
@@ -41,16 +39,14 @@ export const useEditUser = (onSuccess?: () => void) => { | |
| }, | ||
| { | ||
| onSuccess: async (_, variables) => { | ||
| queryClient.invalidateQueries(['getUser']); | ||
| await queryClient.invalidateQueries(['getUser']); | ||
| // If the user changes their project, we need to invalidate the entity descendants query so that recent entities are updated if they change back to the previous project without refreshing the page | ||
| if (variables.projectId) { | ||
| queryClient.invalidateQueries(['entityDescendants']); | ||
| queryClient.invalidateQueries(['tasks']); | ||
|
|
||
| await queryClient.invalidateQueries(['entityDescendants']); | ||
| await queryClient.invalidateQueries(['tasks']); | ||
|
||
| (async () => { | ||
| await models.localSystemFact.addProjectForSync(variables.projectId); | ||
| // Trigger immediate refresh of synced project IDs to enable immediate syncing | ||
| refetchSyncedProjectIds(); | ||
| })(); | ||
chris-bes marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| onSuccess?.(); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1 @@ | ||
| export * from './useDatabaseContext'; | ||
| export * from './useDatabaseEffect'; | ||
| export * from './useProjectsInSync'; |
Uh oh!
There was an error while loading. Please reload this page.