|
|
@@ -34,6 +34,24 @@ const encodeOrg = Schema.encodeSync(Org)
|
|
|
|
|
|
const org = (id: string, name: string) => encodeOrg(new Org({ id: OrgID.make(id), name }))
|
|
|
|
|
|
+const login = () =>
|
|
|
+ new Login({
|
|
|
+ code: DeviceCode.make("device-code"),
|
|
|
+ user: UserCode.make("user-code"),
|
|
|
+ url: "https://one.example.com/verify",
|
|
|
+ server: "https://one.example.com",
|
|
|
+ expiry: Duration.seconds(600),
|
|
|
+ interval: Duration.seconds(5),
|
|
|
+ })
|
|
|
+
|
|
|
+const deviceTokenClient = (body: unknown, status = 400) =>
|
|
|
+ HttpClient.make((req) =>
|
|
|
+ Effect.succeed(req.url === "https://one.example.com/auth/device/token" ? json(req, body, status) : json(req, {}, 404)),
|
|
|
+ )
|
|
|
+
|
|
|
+const poll = (body: unknown, status = 400) =>
|
|
|
+ AccountEffect.Service.use((s) => s.poll(login())).pipe(Effect.provide(live(deviceTokenClient(body, status))))
|
|
|
+
|
|
|
it.effect("orgsByAccount groups orgs per account", () =>
|
|
|
Effect.gen(function* () {
|
|
|
yield* AccountRepo.use((r) =>
|
|
|
@@ -172,15 +190,6 @@ it.effect("config sends the selected org header", () =>
|
|
|
|
|
|
it.effect("poll stores the account and first org on success", () =>
|
|
|
Effect.gen(function* () {
|
|
|
- const login = new Login({
|
|
|
- code: DeviceCode.make("device-code"),
|
|
|
- user: UserCode.make("user-code"),
|
|
|
- url: "https://one.example.com/verify",
|
|
|
- server: "https://one.example.com",
|
|
|
- expiry: Duration.seconds(600),
|
|
|
- interval: Duration.seconds(5),
|
|
|
- })
|
|
|
-
|
|
|
const client = HttpClient.make((req) =>
|
|
|
Effect.succeed(
|
|
|
req.url === "https://one.example.com/auth/device/token"
|
|
|
@@ -198,7 +207,7 @@ it.effect("poll stores the account and first org on success", () =>
|
|
|
),
|
|
|
)
|
|
|
|
|
|
- const res = yield* AccountEffect.Service.use((s) => s.poll(login)).pipe(Effect.provide(live(client)))
|
|
|
+ const res = yield* AccountEffect.Service.use((s) => s.poll(login())).pipe(Effect.provide(live(client)))
|
|
|
|
|
|
expect(res._tag).toBe("PollSuccess")
|
|
|
if (res._tag === "PollSuccess") {
|
|
|
@@ -215,3 +224,59 @@ it.effect("poll stores the account and first org on success", () =>
|
|
|
)
|
|
|
}),
|
|
|
)
|
|
|
+
|
|
|
+for (const [name, body, expectedTag] of [
|
|
|
+ [
|
|
|
+ "pending",
|
|
|
+ {
|
|
|
+ error: "authorization_pending",
|
|
|
+ error_description: "The authorization request is still pending",
|
|
|
+ },
|
|
|
+ "PollPending",
|
|
|
+ ],
|
|
|
+ [
|
|
|
+ "slow",
|
|
|
+ {
|
|
|
+ error: "slow_down",
|
|
|
+ error_description: "Polling too frequently, please slow down",
|
|
|
+ },
|
|
|
+ "PollSlow",
|
|
|
+ ],
|
|
|
+ [
|
|
|
+ "denied",
|
|
|
+ {
|
|
|
+ error: "access_denied",
|
|
|
+ error_description: "The authorization request was denied",
|
|
|
+ },
|
|
|
+ "PollDenied",
|
|
|
+ ],
|
|
|
+ [
|
|
|
+ "expired",
|
|
|
+ {
|
|
|
+ error: "expired_token",
|
|
|
+ error_description: "The device code has expired",
|
|
|
+ },
|
|
|
+ "PollExpired",
|
|
|
+ ],
|
|
|
+] as const) {
|
|
|
+ it.effect(`poll returns ${name} for ${body.error}`, () =>
|
|
|
+ Effect.gen(function* () {
|
|
|
+ const result = yield* poll(body)
|
|
|
+ expect(result._tag).toBe(expectedTag)
|
|
|
+ }),
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
+it.effect("poll returns poll error for other OAuth errors", () =>
|
|
|
+ Effect.gen(function* () {
|
|
|
+ const result = yield* poll({
|
|
|
+ error: "server_error",
|
|
|
+ error_description: "An unexpected error occurred",
|
|
|
+ })
|
|
|
+
|
|
|
+ expect(result._tag).toBe("PollError")
|
|
|
+ if (result._tag === "PollError") {
|
|
|
+ expect(String(result.cause)).toContain("server_error")
|
|
|
+ }
|
|
|
+ }),
|
|
|
+)
|