Skip to content

Commit 83b6ec8

Browse files
committed
wip setup test pds in setup file
1 parent dbc1131 commit 83b6ec8

File tree

4 files changed

+296
-1
lines changed

4 files changed

+296
-1
lines changed
Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
import { describe, expect, it } from 'vitest';
2+
3+
import { CredentialManager, XRPC } from '@atcute/client';
4+
5+
import { Agent } from './agent';
6+
7+
describe('Agent', () => {
8+
it('can be instantiated', async () => {
9+
// @ts-ignore
10+
const manager = new CredentialManager({ service: TEST_PDS_URL });
11+
await manager.login({ identifier: 'alice.test', password: 'password' });
12+
const agent = new Agent(manager);
13+
console.log(`session: ${JSON.stringify(agent.session)}`);
14+
});
15+
16+
it('can connect to a PDS', async () => {
17+
const rpc = new XRPC({
18+
// @ts-ignore
19+
handler: new CredentialManager({ service: TEST_PDS_URL }),
20+
});
21+
22+
const { data } = await rpc.get('com.atproto.server.describeServer', {});
23+
24+
expect(data).toEqual({
25+
did: 'did:web:localhost',
26+
availableUserDomains: ['.test'],
27+
inviteCodeRequired: false,
28+
links: {
29+
privacyPolicy: 'https://bsky.social/about/support/privacy-policy',
30+
termsOfService: 'https://bsky.social/about/support/tos',
31+
},
32+
contact: {},
33+
});
34+
});
35+
});
36+
37+
// describe('CredentialManager', () => {
38+
// it('can login', async () => {
39+
// const onSessionUpdate = vi.fn();
40+
//
41+
// const manager = new CredentialManager({
42+
// service: network.pds.url,
43+
// onSessionUpdate,
44+
// });
45+
// const rpc = new XRPC({ handler: manager });
46+
//
47+
// await expect(
48+
// rpc.get('com.atproto.server.getSession', {}),
49+
// ).rejects.toThrow();
50+
// expect(onSessionUpdate).not.toHaveBeenCalled();
51+
// expect(manager.session).toBe(undefined);
52+
//
53+
// await manager.login({ identifier: 'user1.test', password: 'password' });
54+
//
55+
// await expect(
56+
// rpc.get('com.atproto.server.getSession', {}),
57+
// ).resolves.not.toBe(undefined);
58+
// expect(onSessionUpdate).toHaveBeenCalledOnce();
59+
// expect(manager.session).not.toBe(undefined);
60+
// });
61+
//
62+
// it('can refresh for new tokens', async () => {
63+
// const fetch = vi.fn(globalThis.fetch);
64+
// const onRefresh = vi.fn();
65+
//
66+
// const manager = new CredentialManager({
67+
// service: network.pds.url,
68+
// fetch,
69+
// onRefresh,
70+
// });
71+
// const rpc = new XRPC({ handler: manager });
72+
//
73+
// await manager.login({ identifier: 'user1.test', password: 'password' });
74+
//
75+
// expect(onRefresh).not.toHaveBeenCalled();
76+
//
77+
// const originalJwt = manager.session!.accessJwt;
78+
//
79+
// // Refreshing now would return the same token due to matching timestamp,
80+
// // wait for 1 second.
81+
// await sleep(1_000);
82+
//
83+
// fetch.mockResolvedValueOnce(
84+
// new Response(JSON.stringify({ error: 'ExpiredToken' }), {
85+
// status: 400,
86+
// headers: { 'content-type': 'application/json' },
87+
// }),
88+
// );
89+
//
90+
// await rpc.get('com.atproto.server.getSession', {});
91+
// expect(onRefresh).toHaveBeenCalledOnce();
92+
//
93+
// const refreshedJwt = manager.session!.accessJwt;
94+
//
95+
// expect(refreshedJwt).not.toBe(originalJwt);
96+
// });
97+
//
98+
// it('dedupes token refreshes', async () => {
99+
// const originalFetch = globalThis.fetch;
100+
//
101+
// const fetch = vi.fn(globalThis.fetch);
102+
// const onRefresh = vi.fn();
103+
//
104+
// const manager = new CredentialManager({
105+
// service: network.pds.url,
106+
// fetch,
107+
// onRefresh,
108+
// });
109+
// const rpc = new XRPC({ handler: manager });
110+
//
111+
// await manager.login({ identifier: 'user1.test', password: 'password' });
112+
//
113+
// const originalJwt = manager.session!.accessJwt;
114+
//
115+
// // Refreshing now would return the same token due to matching timestamp,
116+
// // wait for 1 second.
117+
// await sleep(1_000);
118+
//
119+
// let expiredCalls = 0;
120+
// let refreshCalls = 0;
121+
//
122+
// await fetch.withImplementation(
123+
// (input, init) => {
124+
// const request = new Request(input, init);
125+
//
126+
// if (request.headers.get('authorization') === `Bearer ${originalJwt}`) {
127+
// expiredCalls++;
128+
//
129+
// return Promise.resolve(
130+
// new Response(JSON.stringify({ error: 'ExpiredToken' }), {
131+
// status: 400,
132+
// headers: { 'content-type': 'application/json' },
133+
// }),
134+
// );
135+
// }
136+
//
137+
// if (request.url.includes('/xrpc/com.atproto.server.refreshSession')) {
138+
// refreshCalls++;
139+
// }
140+
//
141+
// return originalFetch(request);
142+
// },
143+
// async () => {
144+
// await Promise.all([
145+
// rpc.get('com.atproto.server.getSession', {}),
146+
// rpc.get('com.atproto.server.getSession', {}),
147+
// rpc.get('com.atproto.server.getSession', {}),
148+
// ]);
149+
// },
150+
// );
151+
//
152+
// expect(expiredCalls).toBe(3);
153+
// expect(refreshCalls).toBe(1);
154+
//
155+
// expect(onRefresh).toHaveBeenCalledOnce();
156+
//
157+
// const refreshedJwt = manager.session!.accessJwt;
158+
//
159+
// expect(refreshedJwt).not.toBe(originalJwt);
160+
// });
161+
//
162+
// it('does not mutate session if refresh fails', async () => {
163+
// const originalFetch = globalThis.fetch;
164+
//
165+
// const fetch = vi.fn(globalThis.fetch);
166+
// const onRefresh = vi.fn();
167+
//
168+
// const manager = new CredentialManager({
169+
// service: network.pds.url,
170+
// fetch,
171+
// onRefresh,
172+
// });
173+
// const rpc = new XRPC({ handler: manager });
174+
//
175+
// await manager.login({ identifier: 'user1.test', password: 'password' });
176+
//
177+
// const originalJwt = manager.session!.accessJwt;
178+
//
179+
// // Refreshing now would return the same token due to matching timestamp,
180+
// // wait for 1 second.
181+
// await sleep(1_000);
182+
//
183+
// await fetch.withImplementation(
184+
// (input, init) => {
185+
// const request = new Request(input, init);
186+
//
187+
// if (request.headers.get('authorization') === `Bearer ${originalJwt}`) {
188+
// return Promise.resolve(
189+
// new Response(JSON.stringify({ error: 'ExpiredToken' }), {
190+
// status: 400,
191+
// headers: { 'content-type': 'application/json' },
192+
// }),
193+
// );
194+
// }
195+
//
196+
// if (request.url.includes('/xrpc/com.atproto.server.refreshSession')) {
197+
// return Promise.resolve(new Response(undefined, { status: 500 }));
198+
// }
199+
//
200+
// return originalFetch(request);
201+
// },
202+
// async () => {
203+
// try {
204+
// await rpc.get('com.atproto.server.getSession', {});
205+
// expect.fail(`getSession call should not succeed`);
206+
// } catch (err) {
207+
// if (!(err instanceof XRPCError)) {
208+
// expect.fail(`No errors other than XRPC error should be thrown`);
209+
// }
210+
//
211+
// expect(err.kind).toBe('ExpiredToken');
212+
// }
213+
// },
214+
// );
215+
//
216+
// expect(manager.session).not.toBe(undefined);
217+
// expect(manager.session!.accessJwt).toBe(originalJwt);
218+
//
219+
// expect(onRefresh).not.toHaveBeenCalled();
220+
// });
221+
//
222+
// it('can resume sessions', async () => {
223+
// let session: AtpSessionData;
224+
//
225+
// {
226+
// const manager = new CredentialManager({ service: network.pds.url });
227+
//
228+
// await manager.login({ identifier: 'user1.test', password: 'password' });
229+
// expect(manager.session).not.toBe(undefined);
230+
//
231+
// session = manager.session!;
232+
// }
233+
//
234+
// const fetch = vi.fn(globalThis.fetch);
235+
// expect(fetch).not.toHaveBeenCalled();
236+
//
237+
// {
238+
// const manager = new CredentialManager({
239+
// service: network.pds.url,
240+
// fetch,
241+
// });
242+
//
243+
// await manager.resume(session);
244+
// expect(manager.session).not.toBe(undefined);
245+
// }
246+
//
247+
// expect(fetch).toHaveBeenCalledOnce();
248+
// expect(fetch.mock.lastCall).not.toBe(undefined);
249+
//
250+
// {
251+
// const lastCall = fetch.mock.lastCall!;
252+
// const request = new Request(lastCall[0], lastCall[1]);
253+
//
254+
// expect(request.url).includes('/xrpc/com.atproto.server.getSession');
255+
// }
256+
// });
257+
// });

packages/client/tsconfig.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
"verbatimModuleSyntax": true,
3232
"skipLibCheck": true
3333
},
34-
"include": ["./src/**/*", "./tests/**/*", "./test-utils/**/*"],
34+
"include": ["./src/**/*", "vitest-setup.ts"],
3535
"typedocOptions": {
3636
"out": "./docs",
3737
"theme": "default",

packages/client/vitest-setup.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { afterAll, beforeAll } from 'vitest';
2+
3+
import { CredentialManager, XRPC } from '@atcute/client';
4+
import { TestNetwork } from '@atcute/internal-dev-env';
5+
6+
let network: TestNetwork;
7+
8+
beforeAll(async () => {
9+
network = await TestNetwork.create({});
10+
// TODO: how to avoid ts-ignore?
11+
// @ts-ignore
12+
globalThis.TEST_PDS_URL = network.pds.url;
13+
// @ts-ignore
14+
console.log(`TestNetwork started: ${TEST_PDS_URL}`);
15+
16+
const rpc = new XRPC({
17+
handler: new CredentialManager({ service: network.pds.url }),
18+
});
19+
await createAccount(rpc, 'alice.test');
20+
await createAccount(rpc, 'bob.test');
21+
});
22+
23+
afterAll(async () => {
24+
await network.close();
25+
// @ts-ignore
26+
globalThis.TEST_PDS_URL = undefined;
27+
});
28+
29+
const createAccount = async (rpc: XRPC, handle: string) => {
30+
await rpc.call('com.atproto.server.createAccount', {
31+
data: {
32+
handle: handle,
33+
email: `${handle}@example.com`,
34+
password: 'password',
35+
},
36+
});
37+
};

packages/client/vitest.config.mts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { defineConfig } from 'vitest/config';
22

33
export default defineConfig({
44
test: {
5+
setupFiles: 'vitest-setup.ts',
56
coverage: {
67
provider: 'istanbul',
78
reporter: ['text', 'json-summary', 'json', 'html'],

0 commit comments

Comments
 (0)