diff --git a/test/integration/agent-ca/agent-ca-test.js b/test/integration/agent-ca/agent-ca-test.js deleted file mode 100644 index 35c4d38c..00000000 --- a/test/integration/agent-ca/agent-ca-test.js +++ /dev/null @@ -1,83 +0,0 @@ -const { readFileSync } = require("node:fs"); -const { resolve } = require("node:path"); -const { fetch: undiciFetch, Agent } = require("undici"); - -const { Octokit } = require("../../.."); -const ca = readFileSync(resolve(__dirname, "./ca.crt")); - -describe("custom client certificate", () => { - let server; - before((done) => { - server = https.createServer( - { - key: readFileSync(resolve(__dirname, "./localhost.key")), - cert: readFileSync(resolve(__dirname, "./localhost.crt")), - }, - function (request, response) { - expect(request.method).to.equal("GET"); - expect(request.url).to.equal("/repos/octokit/rest.js"); - - response.writeHead(200); - response.write("ok"); - response.end(); - }, - ); - - server.listen(0, done); - }); - - it("undici.Agent({ca})", () => { - const agent = new Agent({ - keepAliveTimeout: 10, - keepAliveMaxTimeout: 10, - connect: { ca: ca }, - }); - const myFetch = (url, opts) => { - return undiciFetch(url, { - ...opts, - dispatcher: agent, - }); - }; - const octokit = new Octokit({ - baseUrl: "https://localhost:" + server.address().port, - request: { - fetch: myFetch, - }, - }); - - return octokit.rest.repos.get({ - owner: "octokit", - repo: "rest.js", - }); - }); - - it("undici.Agent({ca, rejectUnauthorized})", () => { - const agent = new Agent({ - keepAliveTimeout: 10, - keepAliveMaxTimeout: 10, - connect: { - ca: "invalid", - rejectUnauthorized: true, - }, - }); - const myFetch = (url, opts) => { - return undiciFetch(url, { - ...opts, - dispatcher: agent, - }); - }; - const octokit = new Octokit({ - baseUrl: "https://localhost:" + server.address().port, - request: { - fetch: myFetch, - }, - }); - - return octokit.rest.repos.get({ - owner: "octokit", - repo: "rest.js", - }); - }); - - after((done) => server.close(done)); -}); diff --git a/test/integration/apps-test.js b/test/integration/apps.test.ts similarity index 81% rename from test/integration/apps-test.js rename to test/integration/apps.test.ts index 634cd8f3..b0e3fe10 100644 --- a/test/integration/apps-test.js +++ b/test/integration/apps.test.ts @@ -1,17 +1,17 @@ -const nock = require("nock"); +import { describe, beforeEach, it } from "vitest"; +import nock from "nock"; +import { Octokit } from "../../src/index.ts"; -const { Octokit } = require("../../"); const BEARER_TOKEN = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1NTM4MTkzMTIsImV4cCI6MTU1MzgxOTM3MiwiaXNzIjoxfQ.etiSZ4LFQZ8tiMGJVqKDoGn8hxMCgwL4iLvU5xBUqbAPr4pbk_jJZmMQjuxTlOnRxq4e7NouTizGCdfohRMb3R1mpLzGPzOH9_jqSA_BWYxolsRP_WDSjuNcw6nSxrPRueMVRBKFHrqcTOZJej0djRB5pI61hDZJ_-DGtiOIFexlK3iuVKaqBkvJS5-TbTekGuipJ652g06gXuz-l8i0nHiFJldcuIruwn28hTUrjgtPbjHdSBVn_QQLKc2Fhij8OrhcGqp_D_fvb_KovVmf1X6yWiwXV5VXqWARS-JGD9JTAr2495ZlLV_E4WPxdDpz1jl6XS9HUhMuwBpaCOuipw"; describe("apps", () => { - let octokit; + let octokit: Octokit; beforeEach(() => { octokit = new Octokit({ baseUrl: "https://apps-test-host.com", auth: `Bearer ${BEARER_TOKEN}`, - log: console.log, }); }); @@ -19,7 +19,7 @@ describe("apps", () => { nock("https://apps-test-host.com", { reqheaders: { authorization: `bearer ${BEARER_TOKEN}`, - accept: "application/vnd.github.machine-man-preview+json", + accept: "application/vnd.github.v3+json", }, }) .get("/app") @@ -32,8 +32,7 @@ describe("apps", () => { nock("https://apps-test-host.com", { reqheaders: { authorization: `bearer ${BEARER_TOKEN}`, - accept: - "application/vnd.github.machine-man-preview+json,application/vnd.github.foo-bar-preview+json", + accept: "application/vnd.github.v3+json", }, }) .get("/app") diff --git a/test/integration/authentication-test.js b/test/integration/authentication.test.ts similarity index 93% rename from test/integration/authentication-test.js rename to test/integration/authentication.test.ts index a0cd15c4..2e9f15ca 100644 --- a/test/integration/authentication-test.js +++ b/test/integration/authentication.test.ts @@ -1,9 +1,9 @@ -const lolex = require("lolex"); -const nock = require("nock"); -const { createAppAuth } = require("@octokit/auth-app"); -const { createActionAuth } = require("@octokit/auth-action"); +import { describe, it, expect, vi } from "vitest"; +import nock from "nock"; +import { createAppAuth } from "@octokit/auth-app"; +import { createActionAuth } from "@octokit/auth-action"; -const { Octokit } = require("../.."); +import { Octokit } from "../../src/index.ts"; describe("authentication", () => { it("unauthenticated", () => { @@ -69,6 +69,9 @@ describe("authentication", () => { baseUrl: "https://authentication-test-host.com", auth: "token abc4567", log: { + error() {}, + debug() {}, + info() {}, warn() {}, }, }); @@ -119,7 +122,15 @@ describe("authentication", () => { it("invalid auth errors", () => { expect(() => { - Octokit({ auth: {}, log: { warn() {} } }); + new Octokit({ + auth: {}, + log: { + error() {}, + debug() {}, + info() {}, + warn() {}, + }, + }); }).to.throw(Error); }); @@ -203,7 +214,7 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== .get("/") .reply(200, {}); - const clock = lolex.install({ + const clock = vi.useFakeTimers({ now: 0, toFake: ["Date"], }); @@ -211,14 +222,14 @@ x//0u+zd/R/QRUzLOw4N72/Hu+UG6MNt5iDZFCtapRaKt6OvSBwy8w== const octokit = new Octokit({ authStrategy: createAppAuth, auth: { - id: APP_ID, + appId: APP_ID, privateKey: PRIVATE_KEY, installationId: 123, }, }); return octokit.request("/").then(() => { - clock.uninstall(); + clock.useRealTimers(); }); }); }); diff --git a/test/integration/conditional-request-test.js b/test/integration/conditional-request.test.ts similarity index 82% rename from test/integration/conditional-request-test.js rename to test/integration/conditional-request.test.ts index 7bc4369f..bc7dd4a0 100644 --- a/test/integration/conditional-request-test.js +++ b/test/integration/conditional-request.test.ts @@ -1,9 +1,9 @@ -const nock = require("nock"); - -const { Octokit } = require("../../"); +import { describe, beforeEach, it, expect } from "vitest"; +import nock from "nock"; +import { Octokit } from "../../src/index.ts"; describe("request 304s", () => { - let octokit; + let octokit: Octokit; beforeEach(() => { octokit = new Octokit({ @@ -16,7 +16,7 @@ describe("request 304s", () => { return octokit.rest.orgs .get({ org: "myorg", headers: { "If-None-Match": "etag" } }) - .then((response) => { + .then(() => { expect.fail("should throw error"); }) .catch((error) => { @@ -34,7 +34,7 @@ describe("request 304s", () => { "If-Modified-Since": "Sun Dec 24 2017 22:00:00 GMT-0600 (CST)", }, }) - .then((response) => { + .then(() => { expect.fail("should throw error"); }) .catch((error) => { diff --git a/test/integration/deprecations-test.js b/test/integration/deprecations-test.js deleted file mode 100644 index bff6f054..00000000 --- a/test/integration/deprecations-test.js +++ /dev/null @@ -1,1439 +0,0 @@ -const btoa = require("btoa-lite"); -const nock = require("nock"); - -const DeprecatedOctokit = require("../../"); -const { Octokit } = DeprecatedOctokit; - -const Mocktokit = Octokit.plugin((octokit) => { - octokit.hook.wrap("request", () => null); -}); - -describe("deprecations", () => { - it('const Octokit = require("@octokit/rest")', () => { - let warnCalledCount = 0; - new DeprecatedOctokit({ - log: { - warn: () => { - warnCalledCount++; - }, - }, - }); - - expect(warnCalledCount).to.equal(1); - expect(() => new DeprecatedOctokit()).to.not.throw(); - expect(typeof DeprecatedOctokit.plugin).to.equal("function"); - }); - it("octokit.rest.search.issues() has been renamed to octokit.rest.search.issuesAndPullRequests() (2018-12-27)", () => { - let warnCalledCount = 0; - const octokit = new Mocktokit({ - log: { - warn: (deprecation) => { - warnCalledCount++; - }, - }, - }); - - return Promise.all([ - octokit.rest.search.issues({ q: "foo" }), - octokit.rest.search.issues({ q: "foo" }), - ]).then(() => { - expect(warnCalledCount).to.equal(1); - }); - }); - - it('"number" parameter has been renamed to "issue_number" (2019-04-10)', () => { - nock("https://deprecation-host.com") - .get("/repos/octocat/hello-world/issues/123") - .twice() - .reply(200, {}); - - let warnCalledCount = 0; - const octokit = new Octokit({ - baseUrl: "https://deprecation-host.com", - log: { - warn: (deprecation) => { - warnCalledCount++; - }, - }, - }); - - return Promise.all([ - octokit.rest.issues.get({ - owner: "octocat", - repo: "hello-world", - number: 123, - }), - octokit.rest.issues.get({ - owner: "octocat", - repo: "hello-world", - number: 123, - }), - ]).then(() => { - // Ideally it would only log once, but it’s unclear on how to implement that - // without adding significant complexity - expect(warnCalledCount).to.equal(2); - }); - }); - - it("deprecated parameter: passing both new and deprecated parameter", () => { - nock("https://deprecation-host.com") - .get("/repos/octocat/hello-world/issues/456") - .twice() - .reply(200, {}); - - let warnCalledCount = 0; - const octokit = new Octokit({ - baseUrl: "https://deprecation-host.com", - log: { - warn: (deprecation) => { - warnCalledCount++; - }, - }, - }); - - return octokit.rest.issues - .get({ - owner: "octocat", - repo: "hello-world", - number: 123, - issue_number: 456, - }) - .then(() => { - expect(warnCalledCount).to.equal(1); - }); - }); - - it("deprecated parameter: passing no options", () => { - const octokit = new Octokit(); - - return octokit.rest.issues.get().catch((error) => { - expect(error.status).to.equal(400); - }); - }); - - it("octokit.rest.issues.get.endpoint({owner, repo, number}) returns correct URL and logs deprecation", () => { - let warnCalledCount = 0; - const octokit = new Octokit({ - log: { - warn() { - warnCalledCount++; - }, - }, - }); - - const { url } = octokit.rest.issues.get.endpoint({ - owner: "octocat", - repo: "hello-world", - number: 123, - }); - const options = octokit.rest.issues.get.endpoint.merge({ - owner: "octocat", - repo: "hello-world", - number: 123, - }); - - expect(url).to.equal( - "https://api.github.com/repos/octocat/hello-world/issues/123", - ); - expect(options.url).to.equal("/repos/{owner}/{repo}/issues/{issue_number}"); - expect("number" in options).to.equal(false); - expect(options.issue_number).to.equal(123); - expect(warnCalledCount).to.equal(2); - }); - - it("octokit.paginate(octokit.rest.pulls.listReviews.merge({owner, repo, number}))", () => { - nock("https://deprecation-host.com") - .get("/repos/octocat/hello-world/pulls/123/reviews") - .query({ - per_page: 1, - }) - .reply( - 200, - [ - { - id: "123", - }, - ], - { - Link: '; rel="next", ; rel="last"', - }, - ) - - .get("/repositories/1/pulls/123/reviews") - .query({ - per_page: 1, - page: 2, - }) - .reply( - 200, - { - total_count: 2, - repository_selection: "all", - repositories: [ - { - id: "456", - }, - ], - }, - { - Link: '; rel="first", ; rel="prev"', - }, - ); - - let warnCalledCount = 0; - const octokit = new Octokit({ - baseUrl: "https://deprecation-host.com", - log: { - warn() { - warnCalledCount++; - }, - }, - }); - - const options = octokit.rest.pulls.listReviews.endpoint.merge({ - owner: "octocat", - repo: "hello-world", - number: 123, - per_page: 1, - }); - - return octokit.paginate(options).then((response) => { - expect(warnCalledCount).to.equal(1); - }); - }); - - it("octokit.authenticate(): basic", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - }, - }) - .get("/orgs/myorg") - .reply(200, {}); - - let warnCalledCount = 0; - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - log: { - warn: () => { - warnCalledCount++; - }, - }, - }); - - octokit.authenticate({ - type: "basic", - username: "username", - password: "password", - }); - - octokit.authenticate({ - type: "basic", - username: "username", - password: "password", - }); - - expect(warnCalledCount).to.equal(1); - - return octokit.rest.orgs.get({ org: "myorg" }); - }); - - it("octokit.authenticate(): basic with 2fa", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - }, - }) - .get("/orgs/myorg") - .reply( - 401, - {}, - { - "x-github-otp": "required; app", - }, - ); - - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - "x-github-otp": "123456", - }, - }) - .get("/orgs/myorg") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - log: { - warn: () => {}, - }, - }); - - octokit.authenticate({ - type: "basic", - username: "username", - password: "password", - on2fa() { - return 123456; - }, - }); - - return octokit.rest.orgs.get({ org: "myorg" }); - }); - - it("octokit.authenticate(): basic with async 2fa", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - }, - }) - .get("/orgs/myorg") - .reply( - 401, - {}, - { - "x-github-otp": "required; app", - }, - ); - - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - "x-github-otp": "123456", - }, - }) - .get("/orgs/myorg") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - log: { - warn: () => {}, - }, - }); - - octokit.authenticate({ - type: "basic", - username: "username", - password: "password", - on2fa() { - return Promise.resolve(123456); - }, - }); - - return octokit.rest.orgs.get({ org: "myorg" }); - }); - - it("octokit.authenticate(): basic with 2fa and invalid one-time-password", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - }, - }) - .get("/orgs/myorg") - .reply( - 401, - {}, - { - "x-github-otp": "required; app", - }, - ); - - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - "x-github-otp": "123456", - }, - }) - .get("/orgs/myorg") - .reply( - 401, - {}, - { - "x-github-otp": "required; app", - }, - ); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - log: { - warn: () => {}, - }, - }); - - octokit.authenticate({ - type: "basic", - username: "username", - password: "password", - on2fa() { - return 123456; - }, - }); - - return octokit.rest.orgs - .get({ org: "myorg" }) - - .then(() => { - throw new Error("should not resolve"); - }) - - .catch((error) => { - expect(error.message).to.match(/Invalid one-time password/i); - }); - }); - - it("octokit.authenticate(): basic without 2fa", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - }, - }) - .get("/orgs/myorg") - .reply( - 401, - {}, - { - "x-github-otp": "required; app", - }, - ); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - log: { - warn: () => {}, - }, - }); - - octokit.authenticate({ - type: "basic", - username: "username", - password: "password", - }); - - return octokit.rest.orgs - .get({ org: "myorg" }) - .then(() => { - throw new Error('should fail with "on2fa missing" error'); - }) - .catch((error) => { - expect(error.message).to.equal( - "2FA required, but options.on2fa is not a function. See https://github.com/octokit/rest.js#authentication", - ); - expect(error.status).to.equal(401); - expect(!!error.response.headers).to.equal(true); - expect(!!error.request).to.equal(true); - }); - }); - - it("octokit.authenticate(): token", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "token abc4567", - }, - }) - .get("/orgs/myorg") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - log: { - warn: () => {}, - }, - }); - - octokit.authenticate({ - type: "token", - token: "abc4567", - }); - - return octokit.rest.orgs.get({ org: "myorg" }); - }); - - it("octokit.authenticate(): oauth token", () => { - nock("https://authentication-test-host.com") - .get("/orgs/myorg") - .query({ access_token: "abc4567" }) - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - log: { - warn: () => {}, - }, - }); - - octokit.authenticate({ - type: "oauth", - token: "abc4567", - }); - - return octokit.rest.orgs.get({ org: "myorg" }); - }); - - it("octokit.authenticate(): oauth token with query", () => { - nock("https://authentication-test-host.com") - .get("/orgs/myorg/repos") - .query({ per_page: 1, access_token: "abc4567" }) - .reply(200, []); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - log: { - warn: () => {}, - }, - }); - - octokit.authenticate({ - type: "oauth", - token: "abc4567", - }); - - return octokit.rest.repos.listForOrg({ org: "myorg", per_page: 1 }); - }); - - it("octokit.authenticate(): oauth key & secret", () => { - nock("https://authentication-test-host.com") - .get("/orgs/myorg") - .query({ client_id: "oauthkey", client_secret: "oauthsecret" }) - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - log: { - warn: () => {}, - }, - }); - - octokit.authenticate({ - type: "oauth", - key: "oauthkey", - secret: "oauthsecret", - }); - - return octokit.rest.orgs.get({ org: "myorg" }); - }); - - it("octokit.authenticate(): oauth key & secret with query", () => { - nock("https://authentication-test-host.com") - .get("/") - .query({ - foo: "bar", - client_id: "oauthkey", - client_secret: "oauthsecret", - }) - .reply(200, []); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - log: { - warn: () => {}, - }, - }); - - octokit.authenticate({ - type: "oauth", - key: "oauthkey", - secret: "oauthsecret", - }); - - return octokit.request("/?foo=bar"); - }); - - it("octokit.authenticate(): app", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Bearer abc4567", - }, - }) - .get("/orgs/myorg") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - log: { - warn: () => {}, - }, - }); - - octokit.authenticate({ - type: "app", - token: "abc4567", - }); - - return octokit.rest.orgs.get({ org: "myorg" }); - }); - - it("octokit.authenticate(): without options", () => { - const octokit = new Octokit({ - log: { - warn: () => {}, - }, - }); - - octokit.authenticate(); - }); - - it("octokit.authenticate(): errors", () => { - const octokit = new Octokit({ - log: { - warn: () => {}, - }, - }); - - expect(() => { - octokit.authenticate({}); - }).to.throw(Error); - - expect(() => { - octokit.authenticate({ type: "basic" }); - }).to.throw(Error); - - expect(() => { - octokit.authenticate({ type: "oauth" }); - }).to.throw(Error); - - expect(() => { - octokit.authenticate({ type: "token" }); - }).to.throw(Error); - }); - - it('octokit.authenticate() when "auth" option is set', () => { - let warnCalledWith; - const octokit = new Octokit({ - auth: "token secret123", - log: { - warn: (message) => { - warnCalledWith = message; - }, - }, - }); - - octokit.authenticate({ - type: "token", - token: "secret123", - }); - - expect(warnCalledWith).to.match( - /octokit\.authenticate\(\) is deprecated and has no effect/, - ); - }); - - it("new Octokit({ auth: { username, password, on2fa } })", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - }, - }) - .get("/orgs/myorg") - .reply(200, {}); - - let warnCalledCount = 0; - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: { - username: "username", - password: "password", - on2fa() {}, - }, - log: { - warn: () => { - warnCalledCount++; - }, - }, - }); - - return octokit.rest.orgs - .get({ org: "myorg" }) - .then(() => { - // deprecation is only logged once per process, I couldn't figure out how to reset the counter - // expect(warnCalledCount).to.equal(1); - - return octokit.auth(); - }) - .then((authentication) => { - expect(authentication).to.deep.equal({ - type: "deprecated", - message: - 'Setting the "new Octokit({ auth })" option to an object without also setting the "authStrategy" option is deprecated and will be removed in v17. See (https://octokit.github.io/rest.js/#authentication)', - }); - }); - }); - - it("new Octokit({ auth: { clientId, clientSecret } })", () => { - nock("https://authentication-test-host.com") - .get("/orgs/myorg") - .query({ - client_id: "123", - client_secret: "secret123", - }) - .reply(200, {}); - - let warnCalledCount = 0; - - const { Octokit } = require("../../"); - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: { - clientId: "123", - clientSecret: "secret123", - }, - log: { - warn: () => { - warnCalledCount++; - }, - }, - }); - - return octokit.rest.orgs.get({ org: "myorg" }).then(() => { - // deprecation is only logged once per process, I couldn't figure out how to reset the counter - // expect(warnCalledCount).to.equal(1); - }); - }); - - it("new Octokit({ auth () { /* ... */ } })", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "token secret123", - }, - }) - .get("/orgs/myorg") - .reply(200, {}); - - let warnCalledCount = 0; - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth() { - return "token secret123"; - }, - log: { - warn: () => { - warnCalledCount++; - }, - }, - }); - - return octokit.rest.orgs.get({ org: "myorg" }).then(() => { - // deprecation is only logged once per process, I couldn't figure out how to reset the counter - // expect(warnCalledCount).to.equal(1); - }); - }); - - it("options.auth { username, password } ", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - }, - }) - .get("/") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: { - username: "username", - password: "password", - }, - log: { - warn() {}, - }, - }); - - return octokit.request("/"); - }); - - it("options.auth { username, password, on2fa } with 2fa", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - }, - }) - .get("/") - .reply( - 401, - {}, - { - "x-github-otp": "required; app", - }, - ); - - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - "x-github-otp": "123456", - }, - }) - .get("/") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: { - username: "username", - password: "password", - on2fa() { - return 123456; - }, - }, - }); - - return octokit.request("/"); - }); - - it("options.auth { username, password, on2fa } with async 2fa", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - }, - }) - .get("/") - .reply( - 401, - {}, - { - "x-github-otp": "required; app", - }, - ); - - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - "x-github-otp": "123456", - }, - }) - .get("/") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: { - username: "username", - password: "password", - on2fa() { - return Promise.resolve(123456); - }, - }, - }); - - return octokit.request("/"); - }); - - it("options.auth { username, password, on2fa } with invalid one-time-password", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - }, - }) - .get("/") - .reply( - 401, - {}, - { - "x-github-otp": "required; app", - }, - ); - - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - "x-github-otp": "123456", - }, - }) - .get("/") - .reply( - 401, - {}, - { - "x-github-otp": "required; app", - }, - ); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: { - username: "username", - password: "password", - on2fa() { - return 123456; - }, - }, - }); - - return octokit - .request("/") - - .then(() => { - throw new Error("should not resolve"); - }) - - .catch((error) => { - expect(error.message).to.match(/Invalid one-time password/i); - }); - }); - - it("options.auth { username, password, on2fa } with expiring 2fa", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - }, - }) - .get("/") - .reply( - 401, - {}, - { - "x-github-otp": "required; app", - }, - ); - - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - "x-github-otp": "1", - }, - }) - .get("/") - .reply(200, {}); - - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - "x-github-otp": "1", - }, - }) - .get("/") - .reply( - 401, - {}, - { - "x-github-otp": "required; app", - }, - ); - - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - "x-github-otp": "2", - }, - }) - .get("/") - .reply(200, {}); - - let callCount = 0; - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: { - username: "username", - password: "password", - on2fa() { - return ++callCount; - }, - }, - }); - - return octokit - .request("/") - .then(() => octokit.request("/")) - .then(() => { - expect(callCount).to.equal(2); - }); - }); - - it("options.auth is { username, password }", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - }, - }) - .get("/") - .reply( - 401, - {}, - { - "x-github-otp": "required; app", - }, - ); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: { - username: "username", - password: "password", - }, - }); - - return octokit - .request("/") - - .then(() => { - throw new Error('should fail with "on2fa missing" error'); - }) - - .catch((error) => { - expect(error.message).to.equal( - "2FA required, but options.on2fa is not a function. See https://github.com/octokit/rest.js#authentication", - ); - expect(error.status).to.equal(401); - expect(!!error.response.headers).to.equal(true); - expect(!!error.request).to.equal(true); - }); - }); - - it("options.oauth is object with clientId & clientSecret", () => { - nock("https://authentication-test-host.com") - .get("/") - .query({ client_id: "id123", client_secret: "secret456" }) - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: { - clientId: "id123", - clientSecret: "secret456", - }, - }); - - return octokit.request("/"); - }); - - it('options.oauth is object with clientId & clientSecret with "?" in URL', () => { - nock("https://authentication-test-host.com") - .get("/") - .query({ foo: "bar", client_id: "id123", client_secret: "secret456" }) - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: { - clientId: "id123", - clientSecret: "secret456", - }, - }); - - return octokit.request("/?foo=bar"); - }); - - it("options.auth is function", () => { - nock("https://authentication-test-host-auth-as-function.com", { - reqheaders: { - authorization: "token abc4567", - }, - }) - .get("/") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host-auth-as-function.com", - auth: () => "token abc4567", - }); - - return octokit.request("/"); - }); - - it("options.auth is async function", () => { - nock("https://authentication-test-host-as-async-function.com", { - reqheaders: { - authorization: "token abc4567", - }, - }) - .get("/") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host-as-async-function.com", - auth: () => Promise.resolve("token abc4567"), - }); - - return octokit.request("/"); - }); - - it("options.auth function (throws error)", () => { - const octokit = new Octokit({ - auth() { - throw new Error("test"); - }, - }); - - return octokit - .request("/") - .then(() => { - throw new Error("should not resolve"); - }) - .catch((error) => { - expect(error.message).to.equal("test"); - }); - }); - - /** - * There is a special case for OAuth applications, when `clientId` and `clientSecret` is passed as - * Basic Authorization instead of query parameters. The only routes where that applies share the same - * URL though: `/applications/{client_id}/tokens/{access_token}`. We identify this acception by looking - * for this path. - * - * 1. [Check an authorization](https://docs.github.com/en/rest/reference/apps/#check-an-authorization) - * 2. [Reset an authorization](https://docs.github.com/en/rest/reference/apps/#reset-an-authorization) - * 3. [Revoke an authorization for an application](https://docs.github.com/en/rest/reference/apps/#revoke-an-authorization-for-an-application) - */ - it("OAuth client & secret to check authorization", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic aWQxMjM6c2VjcmV0NDU2", - }, - }) - .get("/applications/id123/tokens/token123") - .reply(200, {}) - .post("/applications/id123/tokens/token123") - .reply(200, {}) - .delete("/applications/id123/tokens/token123") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: { - clientId: "id123", - clientSecret: "secret456", - }, - }); - - const options = { - client_id: "id123", - access_token: "token123", - }; - - return Promise.all([ - octokit.request( - "GET /applications/{client_id}/tokens/{access_token}", - options, - ), - octokit.request( - "POST /applications/{client_id}/tokens/{access_token}", - options, - ), - octokit.request( - "DELETE /applications/{client_id}/tokens/{access_token}", - options, - ), - ]); - }); - - it("options.auth=basic without prefix", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "basic Zm9vLWJhcjpzZWNyZXQ=", - }, - }) - .get("/") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: btoa("foo-bar:secret"), - }); - - return octokit.request("/"); - }); - - it("options.auth=() => token without prefix", () => { - nock( - "https://authentication-test-host-auth-as-function-token-without-prefix.com", - { - reqheaders: { - authorization: "token abc4567", - }, - }, - ) - .get("/") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: - "https://authentication-test-host-auth-as-function-token-without-prefix.com", - auth: () => "abc4567", - }); - - return octokit.request("/"); - }); - - it("options.auth=() => basic without prefix", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "basic Zm9vLWJhcjpzZWNyZXQ=", - }, - }) - .get("/") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: () => btoa("foo-bar:secret"), - }); - - return octokit.request("/"); - }); - - it("options.auth=() => bearer without prefix", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: - "bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1NTM4MTkzMTIsImV4cCI6MTU1MzgxOTM3MiwiaXNzIjoxfQ.etiSZ4LFQZ8tiMGJVqKDoGn8hxMCgwL4iLvU5xBUqbAPr4pbk_jJZmMQjuxTlOnRxq4e7NouTizGCdfohRMb3R1mpLzGPzOH9_jqSA_BWYxolsRP_WDSjuNcw6nSxrPRueMVRBKFHrqcTOZJej0djRB5pI61hDZJ_-DGtiOIFexlK3iuVKaqBkvJS5-TbTekGuipJ652g06gXuz-l8i0nHiFJldcuIruwn28hTUrjgtPbjHdSBVn_QQLKc2Fhij8OrhcGqp_D_fvb_KovVmf1X6yWiwXV5VXqWARS-JGD9JTAr2495ZlLV_E4WPxdDpz1jl6XS9HUhMuwBpaCOuipw", - }, - }) - .get("/app") - .reply(200, {}); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: () => - "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1NTM4MTkzMTIsImV4cCI6MTU1MzgxOTM3MiwiaXNzIjoxfQ.etiSZ4LFQZ8tiMGJVqKDoGn8hxMCgwL4iLvU5xBUqbAPr4pbk_jJZmMQjuxTlOnRxq4e7NouTizGCdfohRMb3R1mpLzGPzOH9_jqSA_BWYxolsRP_WDSjuNcw6nSxrPRueMVRBKFHrqcTOZJej0djRB5pI61hDZJ_-DGtiOIFexlK3iuVKaqBkvJS5-TbTekGuipJ652g06gXuz-l8i0nHiFJldcuIruwn28hTUrjgtPbjHdSBVn_QQLKc2Fhij8OrhcGqp_D_fvb_KovVmf1X6yWiwXV5VXqWARS-JGD9JTAr2495ZlLV_E4WPxdDpz1jl6XS9HUhMuwBpaCOuipw", - }); - - return octokit.request("/app"); - }); - - // deprecated client options - it("agent option", () => { - let warnCalled = false; - const octokit = new Octokit({ - agent: "agent", - log: { - warn: () => { - warnCalled = true; - }, - }, - }); - - octokit.hook.wrap("request", (request, options) => { - expect(options.request.agent).to.equal("agent"); - return "ok"; - }); - - expect(warnCalled).to.equal(true); - - return octokit - .request("/") - - .then((response) => { - expect(response).to.equal("ok"); - }); - }); - - it("timeout option", () => { - let warnCallCount = 0; - const octokit = new Octokit({ - timeout: 123, - log: { - warn: () => { - warnCallCount++; - }, - }, - }); - Octokit({ - timeout: 456, - log: { - warn: () => { - warnCallCount++; - }, - }, - }); - - octokit.hook.wrap("request", (request, options) => { - expect(options.request.timeout).to.equal(123); - return "ok"; - }); - - expect(warnCallCount).to.equal(1); - - return octokit - .request("/") - - .then((response) => { - expect(response).to.equal("ok"); - }); - }); - - it('headers["User-Agent"] option', () => { - let warnCalled = false; - const octokit = new Octokit({ - headers: { - "User-Agent": "blah", - }, - log: { - warn: () => { - warnCalled = true; - }, - }, - }); - - octokit.hook.wrap("request", (request, options) => { - expect(options.headers["user-agent"]).to.match( - /^blah octokit\.js\/0\.0\.0-development /, - ); - return "ok"; - }); - - expect(warnCalled).to.equal(true); - - return octokit - .request("/") - - .then((response) => { - expect(response).to.equal("ok"); - }); - }); - - it("headers.accept option", () => { - const octokit = new Octokit({ - headers: { - accept: - "application/vnd.github.jean-grey-preview+json,application/vnd.github.symmetra-preview+json", - }, - log: { - warn: () => {}, - }, - }); - - octokit.hook.wrap("request", (request, options) => { - expect(options.headers.accept).to.equal( - "application/vnd.github.jean-grey-preview+json,application/vnd.github.symmetra-preview+json", - ); - return "ok"; - }); - - return octokit - .request("/") - - .then((response) => { - expect(response).to.equal("ok"); - }); - }); - - it(".paginate() with results namespace", () => { - nock("https://api.github.com") - .get("/installation/repositories") - .query({ - per_page: 1, - }) - .reply( - 200, - { - total_count: 2, - repository_selection: "all", - repositories: [ - { - id: "123", - }, - ], - }, - { - Link: '; rel="next", ; rel="last"', - }, - ) - - .get("/installation/repositories") - .query({ - per_page: 1, - page: 2, - }) - .reply( - 200, - { - total_count: 2, - repository_selection: "all", - repositories: [ - { - id: "456", - }, - ], - }, - { - Link: '; rel="first", ; rel="prev"', - }, - ) - - .get("/search/issues") - .query({ - q: "repo:web-platform-tests/wpt is:pr is:open updated:>2019-02-26", - per_page: 1, - }) - .reply( - 200, - { - total_count: 2, - incomplete_results: false, - items: [ - { - id: "123", - }, - ], - }, - { - Link: '; rel="next", ; rel="last"', - }, - ) - - .get("/search/issues") - .query({ - q: "repo:web-platform-tests/wpt is:pr is:open updated:>2019-02-26", - per_page: 1, - page: 2, - }) - .reply( - 200, - { - total_count: 2, - incomplete_results: false, - items: [ - { - id: "456", - }, - ], - }, - { - Link: '; rel="first", ; rel="prev"', - }, - ); - - let warnCallCount = 0; - const octokit = new Octokit({ - log: { - warn: (msg) => { - warnCallCount++; - }, - }, - }); - const searchOptions = - octokit.rest.search.issuesAndPullRequests.endpoint.merge({ - q: "repo:web-platform-tests/wpt is:pr is:open updated:>2019-02-26", - per_page: 1, - headers: { - "accept-encoding": "", - }, - }); - const listReposOptions = octokit.rest.apps.listRepos.endpoint.merge({ - per_page: 1, - }); - - return octokit - .paginate(listReposOptions, (result) => { - expect(result.data.incomplete_results).to.equal(undefined); - expect(result.data.repository_selection).to.equal("all"); - expect(result.data.total_count).to.equal(2); - expect(result.data.repositories.length).to.equal(1); - return result; - }) - - .then(() => - octokit.paginate(searchOptions, (result) => { - expect(result.data.incomplete_results).to.equal(false); - expect(result.data.total_count).to.equal(2); - expect(result.data.items.length).to.equal(1); - return result; - }), - ) - - .then(() => { - expect(warnCallCount).to.equal(4); - }); - }); -}); diff --git a/test/integration/pagination-test.js b/test/integration/pagination.test.ts similarity index 96% rename from test/integration/pagination-test.js rename to test/integration/pagination.test.ts index 8d34f3a7..2dc39f06 100644 --- a/test/integration/pagination-test.js +++ b/test/integration/pagination.test.ts @@ -1,6 +1,6 @@ -const nock = require("nock"); - -const { Octokit } = require("../../"); +import { describe, it, expect } from "vitest"; +import nock from "nock"; +import { Octokit } from "../../src/index.ts"; describe("pagination", () => { it(".paginate()", () => { @@ -282,9 +282,10 @@ describe("pagination", () => { ); const octokit = new Octokit(); - const options = octokit.rest.apps.listRepos.endpoint.merge({ - per_page: 1, - }); + const options = + octokit.rest.apps.listReposAccessibleToInstallation.endpoint.merge({ + per_page: 1, + }); return octokit.paginate(options).then((results) => { expect(results).to.deep.equal([{ id: "123" }, { id: "456" }]); @@ -359,9 +360,10 @@ describe("pagination", () => { }); const octokit = new Octokit(); - const options = octokit.rest.apps.listRepos.endpoint.merge({ - per_page: 1, - }); + const options = + octokit.rest.apps.listReposAccessibleToInstallation.endpoint.merge({ + per_page: 1, + }); return octokit.paginate(options).then((results) => { expect(results).to.deep.equal([{ id: "123" }]); @@ -375,6 +377,7 @@ describe("pagination", () => { state: "success", total_count: 2, statuses: [{ id: 1 }, { id: 2 }], + url: "https://api.github.com/repos/octokit/rest.js/commits/abc4567/status", }); const octokit = new Octokit(); diff --git a/test/integration/params-validations-test.js b/test/integration/params-validations-test.js deleted file mode 100644 index be9517b3..00000000 --- a/test/integration/params-validations-test.js +++ /dev/null @@ -1,237 +0,0 @@ -const nock = require("nock"); - -const { Octokit } = require("../../"); - -describe("params validations", () => { - it("octokit.rest.orgs.get({})", () => { - const octokit = new Octokit(); - - return octokit.rest.orgs - .get({}) - - .then(() => { - expect.fail("should throw error"); - }) - - .catch((error) => { - expect(error.message).to.equal( - "Empty value for parameter 'org': undefined", - ); - expect(error.status).to.equal(400); - }); - }); - - it("request error", () => { - const octokit = new Octokit({ - baseUrl: "https://127.0.0.1:8", // port: 8 // officially unassigned port. See https://en.wikipedia.org/wiki/List_of_TCP_and_UDP_port_numbers - }); - - return octokit.rest.orgs - .get({ org: "foo" }) - - .then(() => { - expect.fail("should throw error"); - }) - - .catch((error) => { - expect(error.status).to.equal(500); - expect(error.message).to.equal( - "request to https://127.0.0.1:8/orgs/foo failed, reason: connect ECONNREFUSED 127.0.0.1:8", - ); - }); - }); - - it("invalid value for octokit.rest.issues.list({filter})", () => { - const octokit = new Octokit(); - - return octokit.rest.issues - .list({ filter: "foo" }) - - .then(() => { - expect.fail("should throw error"); - }) - - .catch((error) => { - expect(error.status).to.equal(400); - expect(error.message).to.equal( - "Invalid value for parameter 'filter': \"foo\"", - ); - }); - }); - - it("invalid value for octokit.rest.projects.moveCard({position})", () => { - const octokit = new Octokit(); - - return octokit.rest.projects - .moveCard({ card_id: 123, position: "foo" }) - - .then(() => { - expect.fail("should throw error"); - }) - - .catch((error) => { - expect(error.status).to.equal(400); - expect(error.message).to.equal( - "Invalid value for parameter 'position': \"foo\"", - ); - }); - }); - - it("Not a number for octokit.rest.repos.createCommitComment({..., position})", () => { - const octokit = new Octokit(); - - return octokit.rest.repos - .createCommitComment({ - owner: "foo", - repo: "bar", - commit_sha: "lala", - body: "Sing with me!", - position: "Age Ain’t Nothing", - }) - - .catch((error) => { - expect(error.status).to.equal(400); - expect(error.message).to.equal( - "Invalid value for parameter 'position': \"Age Ain’t Nothing\" is NaN", - ); - }); - }); - - it("Not a valid JSON string for octokit.rest.repos.createHook({..., config})", () => { - const octokit = new Octokit(); - - return octokit.rest.repos - .createHook({ - owner: "foo", - repo: "bar", - name: "captain", - config: "I’m no Je-Son!", - }) - - .then(() => { - expect.fail("should throw error"); - }) - - .catch((error) => { - expect(error.status).to.equal(400); - expect(error.message).to.equal( - "JSON parse error of value for parameter 'config': \"I’m no Je-Son!\"", - ); - }); - }); - - it("Date object for octokit.rest.issues.createMilestone({..., due_on})", () => { - const octokit = new Octokit({ - baseUrl: "https://milestones-test-host.com", - }); - - nock("https://milestones-test-host.com") - .post("/repos/foo/bar/milestones", (body) => { - expect(body.due_on).to.equal("2012-10-09T23:39:01.000Z"); - return true; - }) - .reply(201, {}); - - return octokit.rest.issues.createMilestone({ - owner: "foo", - repo: "bar", - title: "Like a rolling ...", - due_on: new Date("2012-10-09T23:39:01Z"), - }); - }); - - it("Date is passed in correct format for notifications (#716)", () => { - const octokit = new Octokit({ - baseUrl: "https://notifications-test-host.com", - }); - - nock("https://notifications-test-host.com") - .get("/notifications") - .query((query) => { - expect(query).to.eql({ - since: "2018-01-21T23:27:31.000Z", - }); - return true; - }) - .reply(200, {}); - - return octokit.rest.activity.listNotifications({ - since: "2018-01-21T23:27:31.000Z", - }); - }); - - it("octokit.rest.gitdata.createTree() with invalid tree[] object", () => { - const octokit = new Octokit(); - return octokit.rest.gitdata - .createTree({ - owner: "foo", - repo: "bar", - base_tree: "9fb037999f264ba9a7fc6274d15fa3ae2ab98312", - tree: [ - { - type: "foo", - }, - ], - }) - - .then(() => { - expect.fail("should throw error"); - }) - - .catch((error) => { - expect(error.status).to.equal(400); - expect(error.message).to.equal( - "Invalid value for parameter 'tree[0].type': \"foo\"", - ); - }); - }); - - it("octokit.rest.issues.createLabel() with description: null", () => { - const octokit = new Octokit(); - return octokit.rest.issues - .createLabel({ - owner: "foo", - repo: "bar", - name: "baz", - color: "#bada55", - description: null, - }) - - .then(() => { - expect.fail("should throw error"); - }) - - .catch((error) => { - expect(error.status).to.equal(400); - expect(error.message).to.equal("'description' cannot be null"); - }); - }); - - it("does not alter passed options", () => { - const octokit = new Octokit({ - baseUrl: "https://params-test-host.com", - }); - - nock("https://params-test-host.com").get("/orgs/foo").reply(200, {}); - - const options = { - org: "foo", - headers: { - "x-bar": "baz", - }, - }; - return octokit.rest.orgs - .get(options) - .catch(() => { - // ignore error - }) - .then(() => { - expect(options).to.deep.eql({ - org: "foo", - headers: { - "x-bar": "baz", - }, - }); - }); - }); -}); diff --git a/test/integration/plugins-test.js b/test/integration/plugins.test.ts similarity index 85% rename from test/integration/plugins-test.js rename to test/integration/plugins.test.ts index b88d890d..b76f2d50 100644 --- a/test/integration/plugins-test.js +++ b/test/integration/plugins.test.ts @@ -1,22 +1,28 @@ -const { Octokit } = require("../../"); +import { describe, it, expect } from "vitest"; +import { Octokit } from "../../src/index.ts"; describe("plugins", () => { it("gets called in constructor", () => { const MyOctokit = Octokit.plugin((octokit) => { + // @ts-ignore octokit.foo = "bar"; }); const myClient = new MyOctokit(); + // @ts-ignore expect(myClient.foo).to.equal("bar"); }); it("does not override plugins of original constructor", () => { const MyOctokit = Octokit.plugin((octokit) => { + // @ts-ignore octokit.foo = "bar"; }); const myClient = new MyOctokit(); + // @ts-ignore expect(myClient.foo).to.equal("bar"); const octokit = new Octokit(); + // @ts-ignore expect(octokit.foo).to.equal(undefined); }); diff --git a/test/integration/register-endpoints-test.js b/test/integration/register-endpoints-test.js deleted file mode 100644 index a1df8432..00000000 --- a/test/integration/register-endpoints-test.js +++ /dev/null @@ -1,61 +0,0 @@ -const nock = require("nock"); - -const { Octokit } = require("../../"); - -describe("registerEndpoints", () => { - it("optins are not altered in registered endpoint methods", () => { - nock("https://api.github.com") - .get("/repos/octocat/hello-world/issues/123") - .reply(200, {}); - - const octokit = new Octokit({ - log: { - warn: () => {}, - }, - }); - - octokit.registerEndpoints({ - foo: { - bar: { - method: "GET", - params: { - issue_number: { - required: true, - type: "integer", - }, - number: { - alias: "issue_number", - deprecated: true, - type: "integer", - }, - owner: { - required: true, - type: "string", - }, - repo: { - required: true, - type: "string", - }, - }, - url: "/repos/{owner}/{repo}/issues/{issue_number}", - }, - }, - }); - - const options = { - owner: "octocat", - repo: "hello-world", - number: 123, - }; - - const promise = octokit.foo.bar(options); - - expect(options).to.deep.equal({ - owner: "octocat", - repo: "hello-world", - number: 123, - }); - - return promise; - }); -}); diff --git a/test/integration/request-errors-test.js b/test/integration/request-errors.test.ts similarity index 94% rename from test/integration/request-errors-test.js rename to test/integration/request-errors.test.ts index 22dd4b3e..e1284a66 100644 --- a/test/integration/request-errors-test.js +++ b/test/integration/request-errors.test.ts @@ -1,6 +1,6 @@ -const nock = require("nock"); - -const { Octokit } = require("../../"); +import { describe, it, expect } from "vitest"; +import nock from "nock"; +import { Octokit } from "../../src/index.ts"; describe("request errors", () => { it("timeout", () => { @@ -9,7 +9,7 @@ describe("request errors", () => { const octokit = new Octokit({ baseUrl: "https://request-errors-test.com", request: { - timeout: 100, + signal: AbortSignal.timeout(100), }, }); diff --git a/test/integration/smoke.test.ts b/test/integration/smoke.test.ts index 49be069a..9fed5856 100644 --- a/test/integration/smoke.test.ts +++ b/test/integration/smoke.test.ts @@ -10,7 +10,6 @@ describe("Smoke tests", () => { }); it("can be used as a type", () => { - // @ts-expect-error TS6133 Unused variable let octokit: Octokit; octokit = new Octokit(); }); @@ -57,7 +56,7 @@ describe("Smoke tests", () => { expect(octokit.paginate).toBeInstanceOf(Function); }); - it.skip("@octokit/plugin-request-log", () => { + it("@octokit/plugin-request-log", () => { const mock = fetchMock .sandbox() .getOnce("path:/", { status: 200, body: {} }) @@ -93,9 +92,9 @@ describe("Smoke tests", () => { }, () => { expect(consoleStub.debug.mock.calls.length).toEqual(2); - expect(consoleStub.info.mock.calls.length).toEqual(2); + expect(consoleStub.info.mock.calls.length).toEqual(1); expect(consoleStub.warn.mock.calls.length).toEqual(0); - expect(consoleStub.error.mock.calls.length).toEqual(0); + expect(consoleStub.error.mock.calls.length).toEqual(1); }, ); }); diff --git a/test/issues/1134-missing-endpoint-scopes-test.js b/test/issues/1134-missing-endpoint-scopes.test.ts similarity index 68% rename from test/issues/1134-missing-endpoint-scopes-test.js rename to test/issues/1134-missing-endpoint-scopes.test.ts index 2d62fcaa..30bdd132 100644 --- a/test/issues/1134-missing-endpoint-scopes-test.js +++ b/test/issues/1134-missing-endpoint-scopes.test.ts @@ -1,4 +1,5 @@ -const { Octokit } = require("../../"); +import { describe, it, expect } from "vitest"; +import { Octokit } from "../../src/index.ts"; describe("https://github.com/octokit/rest.js/issues/1134", () => { it("octokit.rest.pulls", () => { diff --git a/test/issues/1279-store-otp-send-header-all-requests-test.js b/test/issues/1279-store-otp-send-header-all-requests-test.js deleted file mode 100644 index 4820291d..00000000 --- a/test/issues/1279-store-otp-send-header-all-requests-test.js +++ /dev/null @@ -1,125 +0,0 @@ -const nock = require("nock"); -const { Octokit } = require("../../"); - -describe("https://github.com/octokit/rest.js/issues/1279", () => { - it("2fa code gets stored and passed as header to listAuthorizations", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - }, - }) - .get("/") - .reply( - 401, - {}, - { - "x-github-otp": "required; app", - }, - ); - - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - "x-github-otp": "123456", - }, - }) - .get("/") - .reply(200, {}); - - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - "x-github-otp": "123456", - }, - }) - .get("/authorizations?per_page=100") - .reply(200, []); - - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: { - username: "username", - password: "password", - on2fa() { - return Promise.resolve(123456); - }, - }, - }); - - return octokit.request("/").then(() => { - return octokit.authorization.listAuthorizations({ per_page: 100 }); - }); - }); - - it("prompts for OTP again once OTP code becomes invalid", () => { - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - }, - }) - .get("/") - .reply( - 401, - {}, - { - "x-github-otp": "required; app", - }, - ); - - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - "x-github-otp": "123456", - }, - }) - .get("/") - .reply(200, {}); - - // OTP code now becomes invalid - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - "x-github-otp": "123456", - }, - }) - .get("/authorizations?per_page=100") - .reply( - 401, - {}, - { - "x-github-otp": "required; app", - }, - ); - - nock("https://authentication-test-host.com", { - reqheaders: { - authorization: "Basic dXNlcm5hbWU6cGFzc3dvcmQ=", - "x-github-otp": "123456", - }, - }) - .get("/authorizations?per_page=100") - .reply(200, {}); - - let on2faCalledCounter = 0; - const octokit = new Octokit({ - baseUrl: "https://authentication-test-host.com", - auth: { - username: "username", - password: "password", - on2fa() { - on2faCalledCounter++; - return Promise.resolve(123456); - }, - }, - }); - - return octokit.request("/").then(() => { - expect(on2faCalledCounter).to.equal(1); - return octokit.authorization - .listAuthorizations({ per_page: 100 }) - .then(() => { - expect(on2faCalledCounter).to.equal(2); - }); - }); - }); -}); diff --git a/test/issues/1323-parameter-deprecation-bug-test.js b/test/issues/1323-parameter-deprecation-bug.test.ts similarity index 77% rename from test/issues/1323-parameter-deprecation-bug-test.js rename to test/issues/1323-parameter-deprecation-bug.test.ts index 7b296dab..7fd34e59 100644 --- a/test/issues/1323-parameter-deprecation-bug-test.js +++ b/test/issues/1323-parameter-deprecation-bug.test.ts @@ -1,5 +1,6 @@ -const nock = require("nock"); -const { Octokit } = require("../.."); +import { describe, it } from "vitest"; +import nock from "nock"; +import { Octokit } from "../../src/index.ts"; describe("https://github.com/octokit/rest.js/issues/1323", () => { it("should accept new parameter", () => { diff --git a/test/issues/1497-include-error-message-on-validation-error-test.js b/test/issues/1497-include-error-message-on-validation-error.test.ts similarity index 87% rename from test/issues/1497-include-error-message-on-validation-error-test.js rename to test/issues/1497-include-error-message-on-validation-error.test.ts index 802e60bb..b31d7c2e 100644 --- a/test/issues/1497-include-error-message-on-validation-error-test.js +++ b/test/issues/1497-include-error-message-on-validation-error.test.ts @@ -1,12 +1,12 @@ -const nock = require("nock"); -const { Octokit } = require("../../"); +import { describe, it, expect } from "vitest"; +import nock from "nock"; +import { Octokit } from "../../src/index.ts"; describe("https://github.com/octokit/rest.js/issues/1497", () => { it("octokit.rest.repos.updateBranchProtection()", () => { nock("https://request-errors-test.com", { reqheaders: { - accept: - "application/vnd.github.hellcat-preview+json,application/vnd.github.luke-cage-preview+json,application/vnd.github.zzzax-preview+json", + accept: "application/vnd.github.v3+json", authorization: "token secret123", }, }) @@ -56,7 +56,7 @@ describe("https://github.com/octokit/rest.js/issues/1497", () => { .catch((error) => { expect(error).to.have.property( "message", - `Validation Failed: "Only organization repositories can have users and team restrictions"`, + `Validation Failed: "Only organization repositories can have users and team restrictions" - https://docs.github.com/en/rest/reference/repos/#update-branch-protection`, ); }); }); diff --git a/test/issues/1553-deprecated-teams-methods-test.js b/test/issues/1553-deprecated-teams-methods-test.js deleted file mode 100644 index 28a311ea..00000000 --- a/test/issues/1553-deprecated-teams-methods-test.js +++ /dev/null @@ -1,27 +0,0 @@ -const nock = require("nock"); -const { Octokit } = require("../../"); - -describe("https://github.com/octokit/rest.js/issues/1553", () => { - it.skip("octokit.rest.teams.removeMember()", () => { - const octokit = new Octokit(); - expect(typeof octokit.rest.teams.removeMember).to.equal("function"); - }); - it.skip("octokit.rest.teams.removeMembership()", () => { - const octokit = new Octokit(); - expect(typeof octokit.rest.teams.removeMembership).to.equal("function"); - }); - it.skip("octokit.rest.teams.listMembers()", () => { - const octokit = new Octokit(); - expect(typeof octokit.rest.teams.listMembers).to.equal("function"); - }); - it.skip("octokit.rest.teams.listMembers.endpoint()", () => { - const octokit = new Octokit(); - expect(typeof octokit.rest.teams.listMembers.endpoint).to.equal("function"); - }); - it.skip("octokit.rest.teams.listMembersLegacy.endpoint()", () => { - const octokit = new Octokit(); - expect(typeof octokit.rest.teams.listMembersLegacy.endpoint).to.equal( - "function", - ); - }); -}); diff --git a/test/issues/1553-deprecated-teams-methods.test.ts b/test/issues/1553-deprecated-teams-methods.test.ts new file mode 100644 index 00000000..af61e1ed --- /dev/null +++ b/test/issues/1553-deprecated-teams-methods.test.ts @@ -0,0 +1,34 @@ +import { describe, it, expect } from "vitest"; +import { Octokit } from "../../src/index.ts"; + +describe("https://github.com/octokit/rest.js/issues/1553 is deprecated and removed", () => { + it("octokit.rest.teams.removeMember() is deprecated and removed", () => { + const octokit = new Octokit(); + // @ts-expect-error the function is deprecated and removed + expect(typeof octokit.rest.teams.removeMember).to.equal("undefined"); + }); + it("octokit.rest.teams.removeMembership() is deprecated and removed", () => { + const octokit = new Octokit(); + // @ts-expect-error the function is deprecated and removed + expect(typeof octokit.rest.teams.removeMembership).to.equal("undefined"); + }); + it("octokit.rest.teams.listMembers() is deprecated and removed", () => { + const octokit = new Octokit(); + // @ts-expect-error the function is deprecated and removed + expect(typeof octokit.rest.teams.listMembers).to.equal("undefined"); + }); + it("octokit.rest.teams.listMembers.endpoint() is deprecated and removed", () => { + const octokit = new Octokit(); + // @ts-expect-error the function is deprecated and removed + expect(typeof octokit.rest.teams.listMembers?.endpoint).to.equal( + "undefined", + ); + }); + it("octokit.rest.teams.listMembersLegacy.endpoint() is deprecated and removed", () => { + const octokit = new Octokit(); + // @ts-expect-error the function is deprecated and removed + expect(typeof octokit.rest.teams.listMembersLegacy?.endpoint).to.equal( + "undefined", + ); + }); +}); diff --git a/test/issues/765-remove-milestone-from-issue-test.js b/test/issues/765-remove-milestone-from-issue.test.ts similarity index 81% rename from test/issues/765-remove-milestone-from-issue-test.js rename to test/issues/765-remove-milestone-from-issue.test.ts index c35e18b1..1ec974b2 100644 --- a/test/issues/765-remove-milestone-from-issue-test.js +++ b/test/issues/765-remove-milestone-from-issue.test.ts @@ -1,5 +1,6 @@ -const nock = require("nock"); -const { Octokit } = require("../../"); +import { describe, it, expect } from "vitest"; +import nock from "nock"; +import { Octokit } from "../../src/index.ts"; describe("https://github.com/octokit/rest.js/issues/765", () => { it("octokit.rest.issues.update({..., milestone: null})", () => { diff --git a/test/issues/818-get-installations-test.js b/test/issues/818-get-installations.test.ts similarity index 72% rename from test/issues/818-get-installations-test.js rename to test/issues/818-get-installations.test.ts index 0a82f083..60567eea 100644 --- a/test/issues/818-get-installations-test.js +++ b/test/issues/818-get-installations.test.ts @@ -1,5 +1,6 @@ -const nock = require("nock"); -const { Octokit } = require("../../"); +import { describe, it } from "vitest"; +import nock from "nock"; +import { Octokit } from "../../src/index.ts"; describe("https://github.com/octokit/rest.js/issues/818", () => { it("octokit.rest.apps.listInstallations()", () => { diff --git a/test/issues/826-fail-on-304-test.js b/test/issues/826-fail-on-304.test.ts similarity index 80% rename from test/issues/826-fail-on-304-test.js rename to test/issues/826-fail-on-304.test.ts index c6af4d41..1a5c563b 100644 --- a/test/issues/826-fail-on-304-test.js +++ b/test/issues/826-fail-on-304.test.ts @@ -1,5 +1,6 @@ -const nock = require("nock"); -const { Octokit } = require("../../"); +import { describe, it, expect } from "vitest"; +import nock from "nock"; +import { Octokit } from "../../src/index.ts"; describe("https://github.com/octokit/rest.js/issues/826", () => { it("throws error on 304 responses", () => { @@ -15,7 +16,7 @@ describe("https://github.com/octokit/rest.js/issues/826", () => { org: "octokit", type: "public", }) - .then((response) => { + .then(() => { expect.fail("should throw error"); }) .catch((error) => { diff --git a/test/issues/841-head-request-test.js b/test/issues/841-head-request.test.ts similarity index 87% rename from test/issues/841-head-request-test.js rename to test/issues/841-head-request.test.ts index 50a61d8d..21f0bd5d 100644 --- a/test/issues/841-head-request-test.js +++ b/test/issues/841-head-request.test.ts @@ -1,5 +1,6 @@ -const nock = require("nock"); -const { Octokit } = require("../../"); +import { describe, it, expect } from "vitest"; +import nock from "nock"; +import { Octokit } from "../../src/index.ts"; describe("https://github.com/octokit/rest.js/issues/841", () => { it("supports sending GET requests with method: HEAD", () => { @@ -7,13 +8,13 @@ describe("https://github.com/octokit/rest.js/issues/841", () => { .head("/repos/whatwg/html/pulls/1") .query(true) // GitHub API returns 200 and Content-{Type|Length} headers for HEAD requsets - .reply(200, "", { + .reply(200, { "Content-Type": "application/json; charset=utf-8", "Content-Length": 19137, }) .head("/repos/whatwg/html/pulls/2") .query(true) - .reply(404, "", { + .reply(404, { "Content-Type": "application/json; charset=utf-8", "Content-Length": 120, }); diff --git a/test/issues/861-custom-accept-header-test.js b/test/issues/861-custom-accept-header.test.ts similarity index 82% rename from test/issues/861-custom-accept-header-test.js rename to test/issues/861-custom-accept-header.test.ts index 85626caa..5fcd9504 100644 --- a/test/issues/861-custom-accept-header-test.js +++ b/test/issues/861-custom-accept-header.test.ts @@ -1,11 +1,12 @@ -const nock = require("nock"); -const { Octokit } = require("../../"); +import { describe, it } from "vitest"; +import nock from "nock"; +import { Octokit } from "../../src/index.ts"; describe("https://github.com/octokit/rest.js/issues/861", () => { it("custom accept header", () => { nock("https://issues-861-test.com", { reqheaders: { - accept: "application/vnd.github.antiope-preview+json", + accept: "application/vnd.github.v3+json", authorization: "token 123", }, }) diff --git a/test/issues/922-create-check-with-empty-actions-array-test.js b/test/issues/922-create-check-with-empty-actions-array.test.ts similarity index 84% rename from test/issues/922-create-check-with-empty-actions-array-test.js rename to test/issues/922-create-check-with-empty-actions-array.test.ts index 8ffc9197..38c102ae 100644 --- a/test/issues/922-create-check-with-empty-actions-array-test.js +++ b/test/issues/922-create-check-with-empty-actions-array.test.ts @@ -1,5 +1,6 @@ -const nock = require("nock"); -const { Octokit } = require("../../"); +import { describe, it } from "vitest"; +import nock from "nock"; +import { Octokit } from "../../src/index.ts"; describe("https://github.com/octokit/rest.js/issues/922", () => { it("octokit.rest.issues.update({..., milestone: null})", () => { diff --git a/test/memory-test.js b/test/memory-test.js deleted file mode 100644 index 78618f99..00000000 --- a/test/memory-test.js +++ /dev/null @@ -1,30 +0,0 @@ -// TODO: we don't currently run this test as part of our CI -// as installing leakage broke for recent Node versions. -// We are looking for an alternative. -const { iterate } = require("leakage"); -const { Octokit } = require("../pkg/index.js"); - -const TestOctokit = Octokit.plugin((octokit) => { - // skip sending requests altogether - octokit.hook.wrap("request", () => null); -}); - -describe("memory leaks (relax, tests run slow)", function () { - this.timeout(30000); - - it("creating many instances", () => { - return iterate.async(() => { - const octokit = new TestOctokit(); - - return octokit.request("/"); - }); - }); - - it("one instance, many requests", () => { - const octokit = new TestOctokit(); - - return iterate.async(() => { - return octokit.request("/"); - }); - }); -}); diff --git a/test/memory.test.ts b/test/memory.test.ts new file mode 100644 index 00000000..3f2028fc --- /dev/null +++ b/test/memory.test.ts @@ -0,0 +1,54 @@ +import { Octokit } from "../src/index.ts"; +import { describe, it, expect } from "vitest"; + +const skip = !global.gc; + +const TestOctokit = Octokit.plugin((octokit) => { + // @ts-expect-error skip sending requests altogether + octokit.hook.wrap("request", () => null); +}); + +describe("memory leaks (relax, tests run slow)", { skip }, function () { + it("creating many instances", async () => { + // Initialize first time for more realistic heap size after + { + const octokit = new TestOctokit(); + await octokit.request("/"); + } + + // force a garbage collection for good measures + global.gc!(); + + const preHeapSize = process.memoryUsage().heapUsed; + for (let i = 0; i < 100000; i++) { + const octokit = new TestOctokit(); + await octokit.request("/"); + } + + // force a garbage collection to check if there are any memory leaks + global.gc!(); + + const postHeapSize = process.memoryUsage().heapUsed; + expect(postHeapSize).toBeLessThan(preHeapSize * 1.025); + }, 30000); + + it("one instance, many requests", async () => { + const octokit = new TestOctokit(); + global.gc!(); + + // Initialize first time for more realistic heap size after + { + await octokit.request("/"); + } + const preHeapSize = process.memoryUsage().heapUsed; + for (let i = 0; i < 100000; i++) { + await octokit.request("/"); + } + + // force a garbage collection to check if there are any memory leaks + global.gc!(); + + const postHeapSize = process.memoryUsage().heapUsed; + expect(postHeapSize).toBeLessThan(preHeapSize * 1.025); + }, 30000); +}); diff --git a/test/scenarios/errors.test.ts b/test/scenarios/errors.test.ts index f18ad1e8..fe81f5c6 100644 --- a/test/scenarios/errors.test.ts +++ b/test/scenarios/errors.test.ts @@ -24,7 +24,7 @@ describe("api.github.com", () => { .catch((error) => { expect(error.message).toMatch( new RegExp( - `Validation Failed: {\\"resource\\":\\"Label\\",\\"code\\":\\"invalid\\",\\"field\\":\\"color\\"} - http://localhost:3000/docs\\.github\\.com/[a-z0-9]{10,12}/rest/reference/issues#create-a-label`, + `Validation Failed: {\\"resource\\":\\"Label\\",\\"code\\":\\"invalid\\",\\"field\\":\\"color\\"} - http://localhost:3000/docs\\.github\\.com/[a-z0-9]{8,12}/rest/reference/issues#create-a-label`, ), ); expect(error.response.data.errors).toEqual([ diff --git a/test/scenarios/get-archive.test.ts b/test/scenarios/get-archive.test.ts index 4a3b01ee..8829bb9f 100644 --- a/test/scenarios/get-archive.test.ts +++ b/test/scenarios/get-archive.test.ts @@ -12,10 +12,6 @@ describe.skip("api.github.com", () => { }); }); - if ("cy" in global) { - return it.skip("octokit.rest.repos.archive() (#758)"); - } - it('octokit.rest.repos.downloadTarballArchive({owner: "octokit-fixture-org", repo: "get-archive"})', () => { return octokit.rest.repos .downloadTarballArchive({ diff --git a/test/scenarios/project-cards.test.ts b/test/scenarios/project-cards.test.ts index a5221fac..79858c0a 100644 --- a/test/scenarios/project-cards.test.ts +++ b/test/scenarios/project-cards.test.ts @@ -13,7 +13,7 @@ describe("api.github.com", () => { }); // blocked by renovate/octokit-plugin-rest-endpoint-methods-5.x - it.skip("octokit.rest.projects.*ProjectCard()", () => { + it("octokit.rest.projects.*ProjectCard()", () => { return octokit.rest.projects .createCard({ column_id: 1000, diff --git a/vite.config.js b/vite.config.js index 516c9dfe..989134c3 100644 --- a/vite.config.js +++ b/vite.config.js @@ -2,6 +2,11 @@ import { defineConfig } from "vite"; export default defineConfig({ test: { + poolOptions: { + forks: { + execArgv: ["--expose-gc"] + } + }, coverage: { include: ["src/**/*.ts"], reporter: ["html"],