import { mockClient, promise } from "@xmpp/test"; import parse from "@xmpp/xml/lib/parse.js"; const username = "foo"; const password = "bar"; const credentials = { username, password }; test("No compatible mechanism available", async () => { const { entity } = mockClient({ username, password }); entity.mockInput( FOO , ); const error = await promise(entity, "error"); expect(error instanceof Error).toBe(true); expect(error.message).toBe("SASL: No compatible mechanism available."); }); test("with object credentials", async () => { const { entity } = mockClient({ credentials }); entity.restart = () => { entity.emit("open"); return Promise.resolve(); }; entity.mockInput( PLAIN , ); expect(await promise(entity, "send")).toEqual( AGZvbwBiYXI= , ); entity.mockInput(); }); test("with function credentials", async () => { expect.assertions(2); const mech = "PLAIN"; let promise_authenticate; async function onAuthenticate(authenticate, mechanisms) { expect(mechanisms).toEqual([mech]); await authenticate(credentials, mech); } const { entity } = mockClient({ credentials: onAuthenticate }); entity.restart = () => { entity.emit("open"); return Promise.resolve(); }; entity.mockInput( {mech} , ); expect(await promise(entity, "send")).toEqual( AGZvbwBiYXI= , ); entity.mockInput(); await promise_authenticate; }); test("Mechanism not found", async () => { const { entity } = mockClient({ async credentials(authenticate, _mechanisms) { await authenticate({ username, password }, "foo"); }, }); entity.mockInput( FOO , ); const error = await promise(entity, "error"); expect(error instanceof Error).toBe(true); expect(error.message).toBe("SASL: No compatible mechanism available."); }); test("with function credentials that rejects", (done) => { expect.assertions(1); const mech = "PLAIN"; const error = {}; async function onAuthenticate() { throw error; } const { entity } = mockClient({ credentials: onAuthenticate }); entity.entity.mockInput( {mech} , ); entity.on("error", (err) => { expect(err).toBe(error); done(); }); }); test("failure", async () => { const { entity } = mockClient({ credentials }); entity.mockInput( PLAIN , ); expect(await promise(entity, "send")).toEqual( AGZvbwBiYXI= , ); const failure = ( ); entity.mockInput(failure); const error = await promise(entity, "error"); expect(error instanceof Error).toBe(true); expect(error.name).toBe("SASLError"); expect(error.condition).toBe("some-condition"); expect(error.element).toBe(failure); }); test("prefers SCRAM-SHA-1", async () => { const { entity } = mockClient({ credentials }); entity.mockInput( ANONYMOUS SCRAM-SHA-1 PLAIN , ); const result = await promise(entity, "send"); expect(result.attrs.mechanism).toEqual("SCRAM-SHA-1"); }); test("use ANONYMOUS if username and password are not provided", async () => { const { entity } = mockClient(); entity.mockInput( PLAIN SCRAM-SHA-1 ANONYMOUS , ); const result = await promise(entity, "send"); expect(result.attrs.mechanism).toEqual("ANONYMOUS"); }); test("with whitespaces", async () => { const { entity } = mockClient(); entity.mockInput( parse( ` ANONYMOUS PLAIN SCRAM-SHA-1 `.trim(), ), ); const result = await promise(entity, "send"); expect(result.attrs.mechanism).toEqual("ANONYMOUS"); });