Skip to content

Commit ea0c4ad

Browse files
committed
wip
1 parent ea56994 commit ea0c4ad

File tree

1 file changed

+278
-0
lines changed

1 file changed

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

0 commit comments

Comments
 (0)