Skip to content

Commit

Permalink
🚧 progress: Make all tests pass.
Browse files Browse the repository at this point in the history
  • Loading branch information
make-github-pseudonymous-again committed Dec 18, 2024
1 parent c56d74f commit 5faff06
Show file tree
Hide file tree
Showing 32 changed files with 464 additions and 195 deletions.
10 changes: 10 additions & 0 deletions imports/_test/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import type Document from '../api/Document';
import type Selector from '../api/query/Selector';
import appIsReady from '../app/isReady';
import isAppTest from '../app/isAppTest';
import sleep from '../lib/async/sleep';
import {_navigate} from '../ui/App';
import {getWatchStreamCount} from '../api/query/watch';

export {
default as randomId,
Expand Down Expand Up @@ -86,6 +89,13 @@ export const client = (title, fn) => {
const cleanup = async () => {
await logout();
unmount();
_navigate('/_test/reset')
await sleep(5);
const n = getWatchStreamCount();
if (n !== 0) {
console.warn(`ChangeStream watch count is different from 0 (got ${n})!`);
}
_navigate('/')
await call(reset);
};

Expand Down
2 changes: 1 addition & 1 deletion imports/api/GenericQueryHook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ type GenericQueryHookReturnType<R> = {
};

type GenericQueryHook<R> = (
query: UserQuery<R>,
query: UserQuery<R> | null,
deps: DependencyList,
) => GenericQueryHookReturnType<R>;

Expand Down
9 changes: 9 additions & 0 deletions imports/api/collection/patients.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,15 @@ export const patientFields = patientIdFields
.merge(patientTagFields);
export type PatientFields = schema.infer<typeof patientFields>;

export const patientUpdate = patientFields.merge(
schema.object({
sex: patientFields.shape.sex.nullable(),
deathdateModifiedAt: patientFields.shape.deathdateModifiedAt.nullable(),
deathdate: patientFields.shape.deathdate.nullable(),
})
).partial();
export type PatientUpdate = schema.infer<typeof patientUpdate>;

export const patientComputedFields = schema.object({
normalizedName: schema.string(),
});
Expand Down
4 changes: 2 additions & 2 deletions imports/api/endpoint/patients/update.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {AuthenticationLoggedIn} from '../../Authentication';
import schema from '../../../lib/schema';

import {patientFields, Patients} from '../../collection/patients';
import {patientUpdate, Patients} from '../../collection/patients';
import {computeUpdate, patients} from '../../patients';
import type TransactionDriver from '../../transaction/TransactionDriver';

Expand All @@ -13,7 +13,7 @@ const {sanitize, updateIndex, updateTags} = patients;
export default define({
name: '/api/patients/update',
authentication: AuthenticationLoggedIn,
schema: schema.tuple([schema.string(), patientFields.partial().strict()]),
schema: schema.tuple([schema.string(), patientUpdate.strict()]),
async transaction(db: TransactionDriver, patientId, newfields) {
const owner = this.userId;

Expand Down
20 changes: 16 additions & 4 deletions imports/api/makeObservedQueryHook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,32 @@ const makeObservedQueryHook =
<T>(
Collection: ObservedQueryCacheCollection<T>,
publication: Publication<[string, UserQuery<T>, ObserveOptions | null]>,
observe: ObserveOptions | null = null,
): GenericQueryHook<T> =>
(query: UserQuery<T>, deps: DependencyList) => {
const [loading, setLoading] = useState<boolean>(true);
(query: UserQuery<T> | null, deps: DependencyList) => {
const [loading, setLoading] = useState<boolean>(query !== null);
const [results, setResults] = useState<any[]>([]);
const [dirty, setDirty] = useState<boolean>(false);
const handleRef = useRef<any>(null);

const effectWillTrigger = useChanged(deps);

useEffect(() => {
if (query === null) {
setLoading(false);
setResults([]);
setDirty(false);
return;
}

const id = {};
handleRef.current = id;
setDirty(false);
setLoading(true);

const timestamp = Date.now();
const key = JSON.stringify({timestamp, query});
const handle = subscribe(publication, key, query, null, {
const handle = subscribe(publication, key, query, observe, {
onStop() {
if (handleRef.current === id) {
setDirty(true);
Expand All @@ -55,7 +63,11 @@ const makeObservedQueryHook =
};
}, deps);

return {
return query === null ? {
loading: false,
results: [],
dirty: false,
} : {
loading: effectWillTrigger || loading,
results,
dirty: !effectWillTrigger && dirty,
Expand Down
8 changes: 4 additions & 4 deletions imports/api/makeQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ const makeQuery =
collection: Collection<T, U>,
publication: Publication<[UserQuery<T>]>,
) =>
(query: UserQuery<T>, deps: DependencyList) => {
const isLoading = useSubscription(publication, query);
(query: UserQuery<T> | null, deps: DependencyList) => {
const isLoading = useSubscription(query === null ? null : publication, query);
const loadingSubscription = isLoading();
const [selector, options] = queryToSelectorOptionsPair(query);
const [selector, options] = query === null ? [] : queryToSelectorOptionsPair(query);
const {loading: loadingResults, results} = useCursor(
() => collection.find(selector, options),
() => query === null ? null : collection.find(selector, options),
deps,
);
const loading = loadingSubscription || loadingResults;
Expand Down
2 changes: 1 addition & 1 deletion imports/api/patients/virtualFields.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {type PatientDocument} from '../collection/patients';
import eidParseBirthdate from '../eidParseBirthdate';

const virtualFields = (patient: PatientDocument) => {
const virtualFields = (patient: Omit<PatientDocument, 'deathdate'> & {deathdate?: Date | null}) => {
const birthdate = eidParseBirthdate(patient.birthdate ?? '');
const deathdateModifiedAt = patient.deathdateModifiedAt ?? undefined;
const deathdateLegal = patient.deathdate ?? undefined;
Expand Down
47 changes: 29 additions & 18 deletions imports/api/publication/stopSubscription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,24 @@ const stopSubscription = (
) => {
const entry = get(key);
if (entry === undefined) {
// console.debug({
// what: 'stopSubscription',
// msg: `subscription ${key} already stopped`,
// });
console.debug({
what: 'stopSubscription',
msg: `subscription ${key} already stopped`,
key,
});
return;
}

//console.debug(JSON.stringify({
//what: 'stopSubscription',
//msg: 'request',
//key,
//id: entry.internals.id,
//name: entry.internals.name,
//params: entry.internals.params,
//refCount: entry.refCount,
//}, undefined, 2));

Check warning on line 34 in imports/api/publication/stopSubscription.ts

View check run for this annotation

Codecov / codecov/patch

imports/api/publication/stopSubscription.ts#L33-L34

Added lines #L33 - L34 were not covered by tests
--entry.refCount;
assert(entry.refCount >= 0, `Negative refCount for ${key}.`);
if (onReady !== undefined) entry.onReady.delete(onReady);
Expand All @@ -36,26 +47,26 @@ const stopSubscription = (

if (entry.refCount === 0) {
const sub = entry.internals;
// console.debug({
// what: 'stopSubscription',
// msg: 'refCount === 0',
// id: sub.id,
// name: sub.name,
// params: sub.params,
// });
//console.debug(JSON.stringify({
//what: 'stopSubscription',
//msg: 'refCount === 0',
//id: sub.id,
//name: sub.name,
//params: sub.params,
//}, undefined, 2));
sub.inactive = true;
const prev = _gcQueue.get(sub.id);
if (prev !== undefined) prev.cancel();

const next = defer(() => {
if (sub.inactive) {
// console.debug({
// what: 'stopSubscription',
// msg: 'unsub',
// id: sub.id,
// name: sub.name,
// params: sub.params,
// });
//console.debug(JSON.stringify({
//what: 'stopSubscription',
//msg: 'delete',
//id: sub.id,
//name: sub.name,
//params: sub.params,
//}, undefined, 2));
set(key, undefined);
handle.stop();
debugMeteorSubscriptions();
Expand Down
23 changes: 23 additions & 0 deletions imports/api/publication/subscribe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ const subscribe = <A extends Args>(
...args: [...A, SubscriptionCallbacks?]
): SubscriptionHandle => {
const [params, callbacks] = _parseCallbacks(args);
//console.debug(JSON.stringify({
//what: 'subscribe',
//msg: 'request',
//name,
//params,
//}, undefined, 2));
const key = identify(name, params);
const entry = get(key);
let handle: Meteor.SubscriptionHandle;
Expand All @@ -87,7 +93,24 @@ const subscribe = <A extends Args>(
});
const internals = subscriptionInternals(handle);

Check warning on line 94 in imports/api/publication/subscribe.ts

View check run for this annotation

Codecov / codecov/patch

imports/api/publication/subscribe.ts#L94

Added line #L94 was not covered by tests
set(key, {handle, internals, refCount: 1, onReady, onStop});

//console.debug(JSON.stringify({
//what: 'subscribe',
//msg: 'create',
//key,
//id: internals.id,
//name: internals.name,
//params: internals.params,
//}, undefined, 2));
} else {
//console.debug(JSON.stringify({
//what: 'subscribe',
//msg: 'recycle',
//key,
//id: entry.internals.id,
//name: entry.internals.name,
//params: entry.internals.params,
//}, undefined, 2));
++entry.refCount;
handle = entry.handle;
entry.internals.inactive = false;
Expand Down
8 changes: 6 additions & 2 deletions imports/api/publication/useFind.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import assert from 'assert';

import {type Mongo} from 'meteor/mongo';
import {useMemo, useEffect, type DependencyList, useState} from 'react';
import {useMemo, useEffect, type DependencyList, useState, useDeferredValue} from 'react';

import type Document from '../Document';

Expand Down Expand Up @@ -30,6 +30,7 @@ const useFindClient = <T extends Document, U = T>(
cursor
.observeAsync({
addedAt(document, atIndex, _before) {
assert(!stopped, 'addedAt called after stop');
if (initializing) {
assert(
atIndex === init.length,
Expand All @@ -47,6 +48,7 @@ const useFindClient = <T extends Document, U = T>(

changedAt(newDocument, _oldDocument, atIndex) {
assert(!initializing, `changedAt called during init`);
assert(!stopped, 'changedAt called after stop');
setResults((data) => [
...data.slice(0, atIndex),
newDocument,
Expand All @@ -56,6 +58,7 @@ const useFindClient = <T extends Document, U = T>(

removedAt(_oldDocument, atIndex) {
assert(!initializing, `removedAt called during init`);

Check warning on line 60 in imports/api/publication/useFind.ts

View check run for this annotation

Codecov / codecov/patch

imports/api/publication/useFind.ts#L59-L60

Added lines #L59 - L60 were not covered by tests
assert(!stopped, 'removedAt called after stop');
setResults((data) => [
...data.slice(0, atIndex),
...data.slice(atIndex + 1),
Expand All @@ -64,6 +67,7 @@ const useFindClient = <T extends Document, U = T>(

movedTo(_document, fromIndex, toIndex, _before) {
assert(!initializing, `movedTo called during init`);
assert(!stopped, 'movedTo called after stop');
setResults((data) => {
const doc = data[fromIndex]!;
const copy = [
Expand Down Expand Up @@ -97,7 +101,7 @@ const useFindClient = <T extends Document, U = T>(
};
}, [cursor]);

return {loading, results};
return useDeferredValue(useMemo(() => ({loading, results}), [loading, results]));
};

const useFind = useFindClient;
Expand Down
7 changes: 5 additions & 2 deletions imports/api/query/watch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ const _optionsToPipeline = (options: Options) =>
options.project === undefined ? [] : [{$project: options.project}];

let _watchStreamCount = 0;
let _maxWatchStreamCount = 0;

export const getWatchStreamCount = () => _watchStreamCount;

Check warning on line 121 in imports/api/query/watch.ts

View check run for this annotation

Codecov / codecov/patch

imports/api/query/watch.ts#L118-L121

Added lines #L118 - L121 were not covered by tests
Expand Down Expand Up @@ -145,12 +146,14 @@ const _watchStream = <T extends Document, U = T>(

let open = true;
++_watchStreamCount;
console.debug({_watchStreamCount});
if (_watchStreamCount > _maxWatchStreamCount) {
_maxWatchStreamCount = _watchStreamCount;
console.debug({_watchStreamCount});
}
stream.on('close', () => {
if (open) {
open = false;
--_watchStreamCount;
console.debug({_watchStreamCount});
}
});

Expand Down
27 changes: 19 additions & 8 deletions imports/ui/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';

import {BrowserRouter, Routes, Route} from 'react-router-dom';
import {BrowserRouter, Routes, Route, useNavigate, NavigateFunction, Path} from 'react-router-dom';

import {CacheProvider} from '@emotion/react';
import createCache from '@emotion/cache';
Expand All @@ -26,16 +26,27 @@ export const muiCache = createCache({
prepend: true,
});

export let _navigate: NavigateFunction = (_to: Partial<Path> | string | number) => {
// TODO: This gets called in non-full-app client tests.
console.warn('Using unitialized test-only _navigate function call.');
};

const _Routes = ({children}) => {
_navigate = useNavigate();
return (<Routes>
<Route element={<div>test-only reset page</div>} path="/_test/reset" />
<Route element={{...children}} path="*" />
</Routes>)
};

const Router = isTest()
? ({children}) => (
? ({children}) => {
return (
<BrowserRouter>
<Routes>
<Route element={<div>test</div>} path="/_test" />
<Route element={{...children}} path="*" />
</Routes>
<_Routes>{children}</_Routes>
</BrowserRouter>
)
: BrowserRouter;
)
} : BrowserRouter;

const App = () => {
const theme = useUserTheme();
Expand Down
2 changes: 1 addition & 1 deletion imports/ui/accessibility/addTooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const addTooltip = (
React.forwardRef(({tooltip, ...rest}: Props<typeof Component>, ref) => {
const title = transform(rest, tooltip);

return title ? (
return title !== undefined ? (
<Tooltip title={title}>
<Component ref={ref} {...rest} />
</Tooltip>
Expand Down
2 changes: 2 additions & 0 deletions imports/ui/availability/useAvailability.tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ client(__filename, () => {
const end = addMilliseconds(datetime, duration);

assert.deepEqual(dropOwners(dropIds(result.current.results)), [
// NOTE: Sometimes, only the first item is present when running the
// test.
slot(beginningOfTime(), begin, 0),
slot(begin, end, 1),
slot(end, endOfTime(), 0),
Expand Down
Loading

0 comments on commit 5faff06

Please sign in to comment.