From e08c987260179c86bdf3fad677d3859f9958aa38 Mon Sep 17 00:00:00 2001 From: Jonas Daniels Date: Sat, 30 Mar 2024 14:54:04 -0700 Subject: [PATCH 1/6] tests(storage): update to only run non-network tests if no secret key set --- legacy_packages/storage/test/ipfs.test.ts | 968 +++++++++++----------- 1 file changed, 488 insertions(+), 480 deletions(-) diff --git a/legacy_packages/storage/test/ipfs.test.ts b/legacy_packages/storage/test/ipfs.test.ts index 29f2a2c0f25..0f88a73f686 100644 --- a/legacy_packages/storage/test/ipfs.test.ts +++ b/legacy_packages/storage/test/ipfs.test.ts @@ -10,19 +10,7 @@ require("dotenv-mono").load(); const secretKey = process.env.TW_SECRET_KEY as string; -describe("IPFS", { timeout: 30000 }, async () => { - if (!secretKey) { - throw new Error("TW_SECRET_KEY is not set in the environment variables"); - } - const storage = new ThirdwebStorage({ - secretKey: secretKey, - }); - const authorizedUrls = prepareGatewayUrls( - DEFAULT_GATEWAY_URLS, - undefined, - secretKey, - ); - +describe("storage:utility functions", () => { it("Should replace tokens in tokenized gateway URL", async () => { const url = getGatewayUrlForCid( "https://{cid}.example.com/{path}", @@ -42,383 +30,370 @@ describe("IPFS", { timeout: 30000 }, async () => { "https://example.com/ipfs/bafybeie4vcsw3ew6io6paaltdvwkpcoeyn6uoewvu7op7fhhztpnivqnyy/1.jpg", ); }); +}); - it("Should resolve scheme with gateway URL", async () => { - const uri = `ipfs://QmYtBTkEnTGrzkns2L8R4rL3keowVg3nGcBhPbwrbAWTRP`; - const url = storage.resolveScheme(uri); - expect(url).to.equal( - getGatewayUrlForCid( - authorizedUrls["ipfs://"][0], - "bafybeie4vcsw3ew6io6paaltdvwkpcoeyn6uoewvu7op7fhhztpnivqnyy", - ), +// these cannot run on forks because of the missing secret key env variable +describe.skipIf(!secretKey)( + "storage:functionality", + { timeout: 30000 }, + async () => { + const storage = new ThirdwebStorage({ + secretKey: secretKey, + }); + const authorizedUrls = prepareGatewayUrls( + DEFAULT_GATEWAY_URLS, + undefined, + secretKey, ); - }); - it("Should upload buffer with file number", async () => { - const uri = await storage.upload(readFileSync("test/files/0.jpg"), { - alwaysUpload: true, + it("Should resolve scheme with gateway URL", async () => { + const uri = `ipfs://QmYtBTkEnTGrzkns2L8R4rL3keowVg3nGcBhPbwrbAWTRP`; + const url = storage.resolveScheme(uri); + expect(url).to.equal( + getGatewayUrlForCid( + authorizedUrls["ipfs://"][0], + "bafybeie4vcsw3ew6io6paaltdvwkpcoeyn6uoewvu7op7fhhztpnivqnyy", + ), + ); }); - expect(uri.endsWith("0"), `${uri} does not end with '0'`).to.be.true; - }); - - it("Should upload buffer with name", async () => { - const uri = await storage.upload( - { - name: "0.jpg", - data: readFileSync("test/files/0.jpg"), - }, - { alwaysUpload: true }, - ); - expect(uri.endsWith("0.jpg"), `${uri} does not end with '0.jpg'`).to.be - .true; - }); - - it("Should upload and download JSON object", async () => { - const uri = await storage.upload( - { - name: "Goku", - description: "The strongest human in the world", - properties: [ - { - name: "Strength", - value: "100", - }, - ], - }, - { + it("Should upload buffer with file number", async () => { + const uri = await storage.upload(readFileSync("test/files/0.jpg"), { alwaysUpload: true, - }, - ); - expect(uri.endsWith("0"), `${uri} does not end with '0'`).to.be.true; + }); - const data = await storage.downloadJSON(uri); - expect(data.name).to.equal("Goku"); - expect(data.description).to.equal("The strongest human in the world"); - expect(data.properties.length).to.equal(1); - }); + expect(uri.endsWith("0"), `${uri} does not end with '0'`).to.be.true; + }); - it("Should batch upload strings with names", async () => { - const uris = await storage.uploadBatch( - [ + it("Should upload buffer with name", async () => { + const uri = await storage.upload( { - data: "data1", - name: "first", + name: "0.jpg", + data: readFileSync("test/files/0.jpg"), }, + { alwaysUpload: true }, + ); + expect(uri.endsWith("0.jpg"), `${uri} does not end with '0.jpg'`).to.be + .true; + }); + + it("Should upload and download JSON object", async () => { + const uri = await storage.upload( { - data: "data2", - name: "second", + name: "Goku", + description: "The strongest human in the world", + properties: [ + { + name: "Strength", + value: "100", + }, + ], }, - ], - { - alwaysUpload: true, - }, - ); - - expect(uris[0].endsWith("first"), `${uris[0]} does not end with 'first'`).to - .be.true; - expect(uris[1].endsWith("second"), `${uris[1]} does not end with 'second'`) - .to.be.true; + { + alwaysUpload: true, + }, + ); + expect(uri.endsWith("0"), `${uri} does not end with '0'`).to.be.true; - const data1 = await (await storage.download(uris[0])).text(); - expect(data1).to.equal("data1"); - const data2 = await (await storage.download(uris[1])).text(); - expect(data2).to.equal("data2"); - }); + const data = await storage.downloadJSON(uri); + expect(data.name).to.equal("Goku"); + expect(data.description).to.equal("The strongest human in the world"); + expect(data.properties.length).to.equal(1); + }); - it("Should batch upload buffers with names", async () => { - const uris = await storage.uploadBatch( - [ + it("Should batch upload strings with names", async () => { + const uris = await storage.uploadBatch( + [ + { + data: "data1", + name: "first", + }, + { + data: "data2", + name: "second", + }, + ], { - data: readFileSync("test/files/0.jpg"), - name: "first.jpg", + alwaysUpload: true, }, + ); + + expect(uris[0].endsWith("first"), `${uris[0]} does not end with 'first'`) + .to.be.true; + expect( + uris[1].endsWith("second"), + `${uris[1]} does not end with 'second'`, + ).to.be.true; + + const data1 = await (await storage.download(uris[0])).text(); + expect(data1).to.equal("data1"); + const data2 = await (await storage.download(uris[1])).text(); + expect(data2).to.equal("data2"); + }); + + it("Should batch upload buffers with names", async () => { + const uris = await storage.uploadBatch( + [ + { + data: readFileSync("test/files/0.jpg"), + name: "first.jpg", + }, + { + data: readFileSync("test/files/1.jpg"), + name: "second.jpg", + }, + ], { - data: readFileSync("test/files/1.jpg"), - name: "second.jpg", + alwaysUpload: true, }, - ], - { - alwaysUpload: true, - }, - ); + ); - expect( - uris[0].endsWith("first.jpg"), - `${uris[0]} does not end with 'first.jpg'`, - ).to.be.true; - expect( - uris[1].endsWith("second.jpg"), - `${uris[1]} does not end with '0.jpg'`, - ).to.be.true; - }); + expect( + uris[0].endsWith("first.jpg"), + `${uris[0]} does not end with 'first.jpg'`, + ).to.be.true; + expect( + uris[1].endsWith("second.jpg"), + `${uris[1]} does not end with '0.jpg'`, + ).to.be.true; + }); - it("Should rewrite file names to numbers if specified", async () => { - const uris = await storage.uploadBatch( - [ + it("Should rewrite file names to numbers if specified", async () => { + const uris = await storage.uploadBatch( + [ + { + data: readFileSync("test/files/0.jpg"), + name: "first.jpg", + }, + { + data: readFileSync("test/files/1.jpg"), + name: "second.jpg", + }, + ], { - data: readFileSync("test/files/0.jpg"), - name: "first.jpg", + rewriteFileNames: { + fileStartNumber: 0, + }, + alwaysUpload: true, }, + ); + + expect(uris[0].endsWith("0"), `${uris[0]} does not end with '0'`).to.be + .true; + expect(uris[1].endsWith("1"), `${uris[1]} does not end with '1'`).to.be + .true; + }); + + it("Should rewrite files with non zero start file number", async () => { + const uris = await storage.uploadBatch( + [ + { + data: readFileSync("test/files/0.jpg"), + name: "first.jpg", + }, + { + data: readFileSync("test/files/1.jpg"), + name: "second.jpg", + }, + ], { - data: readFileSync("test/files/1.jpg"), - name: "second.jpg", - }, - ], - { - rewriteFileNames: { - fileStartNumber: 0, + rewriteFileNames: { + fileStartNumber: 5, + }, + alwaysUpload: true, }, - alwaysUpload: true, - }, - ); + ); - expect(uris[0].endsWith("0"), `${uris[0]} does not end with '0'`).to.be - .true; - expect(uris[1].endsWith("1"), `${uris[1]} does not end with '1'`).to.be - .true; - }); + expect(uris[0].endsWith("5"), `${uris[0]} does not end with '5'`).to.be + .true; + expect(uris[1].endsWith("6"), `${uris[1]} does not end with '6'`).to.be + .true; + }); - it("Should rewrite files with non zero start file number", async () => { - const uris = await storage.uploadBatch( - [ + it("Should batch upload JSON objects", async () => { + const uris = await storage.uploadBatch( + [ + { + name: "Goku", + strength: 100, + powerLevel: "Over 9000", + }, + { + name: "Vegeta", + strenth: 90, + powerLevel: "5000", + }, + ], { - data: readFileSync("test/files/0.jpg"), - name: "first.jpg", + alwaysUpload: true, }, + ); + + expect(uris[0].endsWith("0"), `${uris[0]} does not end with '0'`).to.be + .true; + expect(uris[1].endsWith("1"), `${uris[1]} does not end with '0.jpg'`).to + .be.true; + + const data0 = await storage.downloadJSON(uris[0]); + const data1 = await storage.downloadJSON(uris[1]); + + expect(data0.name).to.equal("Goku"); + expect(data1.name).to.equal("Vegeta"); + }); + + it("Should upload an MP4 file", async () => { + const uri = await storage.upload( { - data: readFileSync("test/files/1.jpg"), - name: "second.jpg", + animation_url: readFileSync("test/files/test.mp4"), }, - ], - { - rewriteFileNames: { - fileStartNumber: 5, + { + alwaysUpload: true, }, - alwaysUpload: true, - }, - ); + ); - expect(uris[0].endsWith("5"), `${uris[0]} does not end with '5'`).to.be - .true; - expect(uris[1].endsWith("6"), `${uris[1]} does not end with '6'`).to.be - .true; - }); + expect(uri).to.equal( + "ipfs://QmbaNzUcv7KPgdwq9u2qegcptktpUK6CdRZF72eSjSa6iJ/0", + ); + }); - it("Should batch upload JSON objects", async () => { - const uris = await storage.uploadBatch( - [ + it("Should upload without directory if specified on function", async () => { + const uri = await storage.upload( { - name: "Goku", - strength: 100, - powerLevel: "Over 9000", + name: "Upload Without Directory", + description: "Uploading alone without a directory...", }, { - name: "Vegeta", - strenth: 90, - powerLevel: "5000", + uploadWithoutDirectory: true, + alwaysUpload: true, }, - ], - { - alwaysUpload: true, - }, - ); - - expect(uris[0].endsWith("0"), `${uris[0]} does not end with '0'`).to.be - .true; - expect(uris[1].endsWith("1"), `${uris[1]} does not end with '0.jpg'`).to.be - .true; - - const data0 = await storage.downloadJSON(uris[0]); - const data1 = await storage.downloadJSON(uris[1]); + ); - expect(data0.name).to.equal("Goku"); - expect(data1.name).to.equal("Vegeta"); - }); + expect(uri).to.equal( + "ipfs://QmdnBEP9UFcRfbuAyXFefNccNbuKWTscHrpWZatvqz9VcV", + ); - it("Should upload an MP4 file", async () => { - const uri = await storage.upload( - { - animation_url: readFileSync("test/files/test.mp4"), - }, - { - alwaysUpload: true, - }, - ); + const json = await storage.downloadJSON(uri); - expect(uri).to.equal( - "ipfs://QmbaNzUcv7KPgdwq9u2qegcptktpUK6CdRZF72eSjSa6iJ/0", - ); - }); + expect(json.name).to.equal("Upload Without Directory"); + expect(json.description).to.equal( + "Uploading alone without a directory...", + ); + }); - it("Should upload without directory if specified on function", async () => { - const uri = await storage.upload( - { - name: "Upload Without Directory", - description: "Uploading alone without a directory...", - }, - { - uploadWithoutDirectory: true, - alwaysUpload: true, - }, - ); + it("Should throw an error on upload without directory with multiple uploads", async () => { + try { + await storage.uploadBatch( + [readFileSync("test/files/0.jpg"), readFileSync("test/files/1.jpg")], + { + uploadWithoutDirectory: true, + alwaysUpload: true, + }, + ); + expect.fail( + "Failed to throw an error on uploading multiple files without directory", + ); + } catch (err: any) { + expect(err.message).to.contain( + "[UPLOAD_WITHOUT_DIRECTORY_ERROR] Cannot upload more than one file or object without directory!", + ); + } + }); - expect(uri).to.equal( - "ipfs://QmdnBEP9UFcRfbuAyXFefNccNbuKWTscHrpWZatvqz9VcV", - ); + it("Should replace gateway URLs with schemes on upload", async () => { + const uri = await storage.upload( + { + image: getGatewayUrlForCid( + authorizedUrls["ipfs://"][0], + `QmbaNzUcv7KPgdwq9u2qegcptktpUK6CdRZF72eSjSa6iJ/0`, + ), + }, + { + alwaysUpload: true, + }, + ); - const json = await storage.downloadJSON(uri); + const res = await storage.download(uri); + const json = await res.json(); - expect(json.name).to.equal("Upload Without Directory"); - expect(json.description).to.equal("Uploading alone without a directory..."); - }); + expect(json.image).to.equal( + "ipfs://bafybeigevrfayusjh2nvk7fqlydj6m3wcagluen5mizxewr6zfx2qk2sy4/0", + ); + }); - it("Should throw an error on upload without directory with multiple uploads", async () => { - try { - await storage.uploadBatch( - [readFileSync("test/files/0.jpg"), readFileSync("test/files/1.jpg")], + it("Should replace schemes with gateway URLs on download", async () => { + const uri = await storage.upload( + { + image: "ipfs://QmbaNzUcv7KPgdwq9u2qegcptktpUK6CdRZF72eSjSa6iJ/0", + }, { - uploadWithoutDirectory: true, alwaysUpload: true, }, ); - expect.fail( - "Failed to throw an error on uploading multiple files without directory", - ); - } catch (err: any) { - expect(err.message).to.contain( - "[UPLOAD_WITHOUT_DIRECTORY_ERROR] Cannot upload more than one file or object without directory!", - ); - } - }); - it("Should replace gateway URLs with schemes on upload", async () => { - const uri = await storage.upload( - { - image: getGatewayUrlForCid( + const json = await storage.downloadJSON(uri); + + expect(json.image).to.equal( + getGatewayUrlForCid( authorizedUrls["ipfs://"][0], `QmbaNzUcv7KPgdwq9u2qegcptktpUK6CdRZF72eSjSa6iJ/0`, ), - }, - { - alwaysUpload: true, - }, - ); - - const res = await storage.download(uri); - const json = await res.json(); - - expect(json.image).to.equal( - "ipfs://bafybeigevrfayusjh2nvk7fqlydj6m3wcagluen5mizxewr6zfx2qk2sy4/0", - ); - }); - - it("Should replace schemes with gateway URLs on download", async () => { - const uri = await storage.upload( - { - image: "ipfs://QmbaNzUcv7KPgdwq9u2qegcptktpUK6CdRZF72eSjSa6iJ/0", - }, - { - alwaysUpload: true, - }, - ); - - const json = await storage.downloadJSON(uri); - - expect(json.image).to.equal( - getGatewayUrlForCid( - authorizedUrls["ipfs://"][0], - `QmbaNzUcv7KPgdwq9u2qegcptktpUK6CdRZF72eSjSa6iJ/0`, - ), - ); - }); - - it("Should upload files with gateway URLs if specified on class", async () => { - const uploader = new IpfsUploader({ - uploadWithGatewayUrl: true, - secretKey, - }); - const singleStorage = new ThirdwebStorage({ - uploader, - secretKey, + ); }); - const _authorizedUrls = prepareGatewayUrls( - DEFAULT_GATEWAY_URLS, - undefined, - secretKey, - ); - const uri = await singleStorage.upload( - { - // Gateway URLs should first be converted back to ipfs:// and then all ipfs:// should convert to first gateway URL - image: readFileSync("test/files/0.jpg"), - animation_url: - "ipfs://QmbaNzUcv7KPgdwq9u2qegcptktpUK6CdRZF72eSjSa6iJ/0", - }, - { - alwaysUpload: true, - }, - ); + it("Should upload files with gateway URLs if specified on class", async () => { + const uploader = new IpfsUploader({ + uploadWithGatewayUrl: true, + secretKey, + }); + const singleStorage = new ThirdwebStorage({ + uploader, + secretKey, + }); + const _authorizedUrls = prepareGatewayUrls( + DEFAULT_GATEWAY_URLS, + undefined, + secretKey, + ); - const res = await singleStorage.download(uri); - const json = await res.json(); + const uri = await singleStorage.upload( + { + // Gateway URLs should first be converted back to ipfs:// and then all ipfs:// should convert to first gateway URL + image: readFileSync("test/files/0.jpg"), + animation_url: + "ipfs://QmbaNzUcv7KPgdwq9u2qegcptktpUK6CdRZF72eSjSa6iJ/0", + }, + { + alwaysUpload: true, + }, + ); - expect(json.image).to.equal( - getGatewayUrlForCid( - _authorizedUrls["ipfs://"][0], - `QmcCJC4T37rykDjR6oorM8hpB9GQWHKWbAi2YR1uTabUZu/0`, - ), - ); - expect(json.animation_url).to.equal( - getGatewayUrlForCid( - _authorizedUrls["ipfs://"][0], - `QmbaNzUcv7KPgdwq9u2qegcptktpUK6CdRZF72eSjSa6iJ/0`, - ), - ); - }); + const res = await singleStorage.download(uri); + const json = await res.json(); - it("Should upload files with gateway URLs if specified on function", async () => { - const uri = await storage.upload( - { - // Gateway URLs should first be converted back to ipfs:// and then all ipfs:// should convert to first gateway URL - image: getGatewayUrlForCid( - authorizedUrls["ipfs://"][0], + expect(json.image).to.equal( + getGatewayUrlForCid( + _authorizedUrls["ipfs://"][0], + `QmcCJC4T37rykDjR6oorM8hpB9GQWHKWbAi2YR1uTabUZu/0`, + ), + ); + expect(json.animation_url).to.equal( + getGatewayUrlForCid( + _authorizedUrls["ipfs://"][0], `QmbaNzUcv7KPgdwq9u2qegcptktpUK6CdRZF72eSjSa6iJ/0`, ), - animation_url: - "ipfs://QmbaNzUcv7KPgdwq9u2qegcptktpUK6CdRZF72eSjSa6iJ/0", - }, - { - uploadWithGatewayUrl: true, - alwaysUpload: true, - }, - ); - - const res = await storage.download(uri); - const json = await res.json(); - - expect(json.image).to.equal( - getGatewayUrlForCid( - authorizedUrls["ipfs://"][0], - `QmbaNzUcv7KPgdwq9u2qegcptktpUK6CdRZF72eSjSa6iJ/0`, - ), - ); - expect(json.animation_url).to.equal( - getGatewayUrlForCid( - authorizedUrls["ipfs://"][0], - `QmbaNzUcv7KPgdwq9u2qegcptktpUK6CdRZF72eSjSa6iJ/0`, - ), - ); - }); + ); + }); - // only run this in CI because on local it will always be different (different api key) - it.runIf(process.env.CI)( - "Should return URIs with gateway URLs if specified on function", - async () => { + it("Should upload files with gateway URLs if specified on function", async () => { const uri = await storage.upload( { - name: "String", - image: readFileSync("test/files/0.jpg"), + // Gateway URLs should first be converted back to ipfs:// and then all ipfs:// should convert to first gateway URL + image: getGatewayUrlForCid( + authorizedUrls["ipfs://"][0], + `QmbaNzUcv7KPgdwq9u2qegcptktpUK6CdRZF72eSjSa6iJ/0`, + ), + animation_url: + "ipfs://QmbaNzUcv7KPgdwq9u2qegcptktpUK6CdRZF72eSjSa6iJ/0", }, { uploadWithGatewayUrl: true, @@ -426,202 +401,235 @@ describe("IPFS", { timeout: 30000 }, async () => { }, ); - expect(uri).to.equal( + const res = await storage.download(uri); + const json = await res.json(); + + expect(json.image).to.equal( getGatewayUrlForCid( authorizedUrls["ipfs://"][0], - // CID changes based on file contents (prod gateway vs staging gateway since they get written) - `bafybeianhuee7lsl5yuga42ewup4bg4uccilo2qpjiqlf5jcxj6bra32yu/0`, + `QmbaNzUcv7KPgdwq9u2qegcptktpUK6CdRZF72eSjSa6iJ/0`, + ), + ); + expect(json.animation_url).to.equal( + getGatewayUrlForCid( + authorizedUrls["ipfs://"][0], + `QmbaNzUcv7KPgdwq9u2qegcptktpUK6CdRZF72eSjSa6iJ/0`, ), ); - }, - ); - - it("Should return URIs with gateway URLs if specified on class", async () => { - const uploader = new IpfsUploader({ - uploadWithGatewayUrl: true, - secretKey, - }); - const storageSingleton = new ThirdwebStorage({ - uploader, - secretKey, }); - const _authorizedUrls = prepareGatewayUrls( - DEFAULT_GATEWAY_URLS, - undefined, - secretKey, - ); - const uri = await storageSingleton.upload( - readFileSync("test/files/0.jpg"), - { alwaysUpload: true }, - ); - - expect(uri).to.equal( - getGatewayUrlForCid( - _authorizedUrls["ipfs://"][0], - `QmcCJC4T37rykDjR6oorM8hpB9GQWHKWbAi2YR1uTabUZu/0`, - ), - ); - }); - - it("Should throw an error when trying to upload different files with the same name", async () => { - try { - await storage.uploadBatch( - [ + // only run this in CI because on local it will always be different (different api key) + it.runIf(process.env.CI)( + "Should return URIs with gateway URLs if specified on function", + async () => { + const uri = await storage.upload( { - data: readFileSync("test/files/0.jpg"), - name: "0.jpg", + name: "String", + image: readFileSync("test/files/0.jpg"), }, { - data: readFileSync("test/files/1.jpg"), - name: "0.jpg", + uploadWithGatewayUrl: true, + alwaysUpload: true, }, - ], - { - alwaysUpload: true, - }, - ); - expect.fail("Uploading files with same name did not throw an error."); - } catch (err: any) { - expect(err.message).to.contain( - "[DUPLICATE_FILE_NAME_ERROR] File name 0.jpg", - ); - } - }); - - it("Should allow to batch upload the same file multiple times even if they have the same name", async () => { - const fileNameWithBufferOne = { - name: "0.jpg", - data: readFileSync("test/files/0.jpg"), - }; - const fileNameWithBufferTwo = { - name: "0.jpg", - data: readFileSync("test/files/0.jpg"), - }; - - const uris = await storage.uploadBatch( - [fileNameWithBufferOne, fileNameWithBufferTwo], - { - alwaysUpload: true, + ); + + expect(uri).to.equal( + getGatewayUrlForCid( + authorizedUrls["ipfs://"][0], + // CID changes based on file contents (prod gateway vs staging gateway since they get written) + `bafybeianhuee7lsl5yuga42ewup4bg4uccilo2qpjiqlf5jcxj6bra32yu/0`, + ), + ); }, ); - expect(uris[0]).to.equal(uris[1]); - }); + it("Should return URIs with gateway URLs if specified on class", async () => { + const uploader = new IpfsUploader({ + uploadWithGatewayUrl: true, + secretKey, + }); + const storageSingleton = new ThirdwebStorage({ + uploader, + secretKey, + }); + const _authorizedUrls = prepareGatewayUrls( + DEFAULT_GATEWAY_URLS, + undefined, + secretKey, + ); - it("Should recursively upload and replace files", async () => { - // Should test nested within objects and arrays - const uris = await storage.uploadBatch( - [ - { - image: readFileSync("test/files/0.jpg"), - properties: [ + const uri = await storageSingleton.upload( + readFileSync("test/files/0.jpg"), + { alwaysUpload: true }, + ); + + expect(uri).to.equal( + getGatewayUrlForCid( + _authorizedUrls["ipfs://"][0], + `QmcCJC4T37rykDjR6oorM8hpB9GQWHKWbAi2YR1uTabUZu/0`, + ), + ); + }); + + it("Should throw an error when trying to upload different files with the same name", async () => { + try { + await storage.uploadBatch( + [ { - image: readFileSync("test/files/1.jpg"), + data: readFileSync("test/files/0.jpg"), + name: "0.jpg", }, { - animation_url: readFileSync("test/files/2.jpg"), + data: readFileSync("test/files/1.jpg"), + name: "0.jpg", }, ], - }, + { + alwaysUpload: true, + }, + ); + expect.fail("Uploading files with same name did not throw an error."); + } catch (err: any) { + expect(err.message).to.contain( + "[DUPLICATE_FILE_NAME_ERROR] File name 0.jpg", + ); + } + }); + + it("Should allow to batch upload the same file multiple times even if they have the same name", async () => { + const fileNameWithBufferOne = { + name: "0.jpg", + data: readFileSync("test/files/0.jpg"), + }; + const fileNameWithBufferTwo = { + name: "0.jpg", + data: readFileSync("test/files/0.jpg"), + }; + + const uris = await storage.uploadBatch( + [fileNameWithBufferOne, fileNameWithBufferTwo], { - image: readFileSync("test/files/3.jpg"), - properties: [ - readFileSync("test/files/4.jpg"), - readFileSync("test/files/test.mp4"), - ], + alwaysUpload: true, }, - ], - { - alwaysUpload: true, - }, - ); + ); - expect(uris[0]).to.equal( - "ipfs://QmTtEY2WSTDpzYSXw2G3xsYw3eMs8YephvrfVYd8qia9F9/0", - ); - expect(uris[1]).to.equal( - "ipfs://QmTtEY2WSTDpzYSXw2G3xsYw3eMs8YephvrfVYd8qia9F9/1", - ); - }); + expect(uris[0]).to.equal(uris[1]); + }); - it("Should successfully upload string", async () => { - const metadata = - '{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"}'; - const uri = await storage.upload(metadata, { - alwaysUpload: true, + it("Should recursively upload and replace files", async () => { + // Should test nested within objects and arrays + const uris = await storage.uploadBatch( + [ + { + image: readFileSync("test/files/0.jpg"), + properties: [ + { + image: readFileSync("test/files/1.jpg"), + }, + { + animation_url: readFileSync("test/files/2.jpg"), + }, + ], + }, + { + image: readFileSync("test/files/3.jpg"), + properties: [ + readFileSync("test/files/4.jpg"), + readFileSync("test/files/test.mp4"), + ], + }, + ], + { + alwaysUpload: true, + }, + ); + + expect(uris[0]).to.equal( + "ipfs://QmTtEY2WSTDpzYSXw2G3xsYw3eMs8YephvrfVYd8qia9F9/0", + ); + expect(uris[1]).to.equal( + "ipfs://QmTtEY2WSTDpzYSXw2G3xsYw3eMs8YephvrfVYd8qia9F9/1", + ); }); - const data = await (await storage.download(uri)).text(); - expect(data).to.equal(metadata); + it("Should successfully upload string", async () => { + const metadata = + '{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"}'; + const uri = await storage.upload(metadata, { + alwaysUpload: true, + }); + const data = await (await storage.download(uri)).text(); - const json = await storage.downloadJSON(uri); - expect(JSON.stringify(json)).to.equal(metadata); - }); + expect(data).to.equal(metadata); - it("Should succesfully upload boolean", async () => { - const uri = await storage.upload(false, { - alwaysUpload: true, + const json = await storage.downloadJSON(uri); + expect(JSON.stringify(json)).to.equal(metadata); }); - const data = await storage.downloadJSON(uri); - expect(data).to.equal(false); - }); + it("Should succesfully upload boolean", async () => { + const uri = await storage.upload(false, { + alwaysUpload: true, + }); + const data = await storage.downloadJSON(uri); - it("Should succesfully upload number", async () => { - const uri = await storage.upload(42, { - alwaysUpload: true, + expect(data).to.equal(false); }); - const data = await storage.downloadJSON(uri); - expect(data).to.equal(42); - }); + it("Should succesfully upload number", async () => { + const uri = await storage.upload(42, { + alwaysUpload: true, + }); + const data = await storage.downloadJSON(uri); - it("Should succesfully upload null", async () => { - const uri = await storage.upload(null, { - alwaysUpload: true, + expect(data).to.equal(42); }); - const data = await storage.downloadJSON(uri); - expect(data).to.equal(null); - }); + it("Should succesfully upload null", async () => { + const uri = await storage.upload(null, { + alwaysUpload: true, + }); + const data = await storage.downloadJSON(uri); - it("Should succesfully upload array", async () => { - const uri = await storage.upload(["Name", "Description"], { - alwaysUpload: true, + expect(data).to.equal(null); }); - const data = await storage.downloadJSON(uri); - expect(Array.isArray(data)).to.equal(true); - expect(data.length).to.equal(2); - expect(data[0]).to.equal("Name"); - expect(data[1]).to.equal("Description"); - }); + it("Should succesfully upload array", async () => { + const uri = await storage.upload(["Name", "Description"], { + alwaysUpload: true, + }); + const data = await storage.downloadJSON(uri); - it("Should not upload undefined", async () => { - const uri = await storage.upload(undefined, { - alwaysUpload: true, + expect(Array.isArray(data)).to.equal(true); + expect(data.length).to.equal(2); + expect(data[0]).to.equal("Name"); + expect(data[1]).to.equal("Description"); }); - expect(uri).to.equal(undefined); - }); - it("should successfully upload files with special characters in their file names", async () => { - const bufferWithSpecialCharFileName = { - name: "#specialChar^file$Name.jpg", - data: readFileSync("test/files/0.jpg"), - }; - const uri = await storage.upload(bufferWithSpecialCharFileName, { - alwaysUpload: true, + it("Should not upload undefined", async () => { + const uri = await storage.upload(undefined, { + alwaysUpload: true, + }); + expect(uri).to.equal(undefined); }); - const fileNameEncoded = uri.split("/").at(-1); + it("should successfully upload files with special characters in their file names", async () => { + const bufferWithSpecialCharFileName = { + name: "#specialChar^file$Name.jpg", + data: readFileSync("test/files/0.jpg"), + }; + const uri = await storage.upload(bufferWithSpecialCharFileName, { + alwaysUpload: true, + }); - expect(fileNameEncoded).to.equal( - encodeURIComponent(bufferWithSpecialCharFileName.name), - ); + const fileNameEncoded = uri.split("/").at(-1); - const res = await storage.download(uri); + expect(fileNameEncoded).to.equal( + encodeURIComponent(bufferWithSpecialCharFileName.name), + ); - expect(res.status).to.equal(200); - }); -}); + const res = await storage.download(uri); + + expect(res.status).to.equal(200); + }); + }, +); From 708aa6d56c73a11a5dfbc12ce34523876f5b0e4a Mon Sep 17 00:00:00 2001 From: Jonas Daniels Date: Sat, 30 Mar 2024 15:02:05 -0700 Subject: [PATCH 2/6] test: skip test suites without secret key during unit tests --- .../deployment/deploy-via-autofactory.test.ts | 4 +- .../deployment/utils/bootstrap.test.ts | 4 +- .../src/event/actions/get-events.test.ts | 4 +- .../prebuilts/deploy-erc1155.test.ts | 82 ++++++------- .../extensions/prebuilts/deploy-erc20.test.ts | 82 ++++++------- .../prebuilts/deploy-erc721.test.ts | 114 +++++++++--------- .../send-and-confirm-transaction.test.ts | 4 +- .../transaction/prepare-transaction.test.ts | 39 +++--- .../src/utils/bytecode/extractIPFS.test.ts | 11 +- turbo.json | 2 +- 10 files changed, 171 insertions(+), 175 deletions(-) diff --git a/packages/thirdweb/src/contract/deployment/deploy-via-autofactory.test.ts b/packages/thirdweb/src/contract/deployment/deploy-via-autofactory.test.ts index 3f7e3605eb8..1ee44f86c60 100644 --- a/packages/thirdweb/src/contract/deployment/deploy-via-autofactory.test.ts +++ b/packages/thirdweb/src/contract/deployment/deploy-via-autofactory.test.ts @@ -12,7 +12,9 @@ import { prepareAutoFactoryDeployTransaction } from "./deploy-via-autofactory.js import { initialize } from "../../extensions/prebuilts/__generated__/DropERC721/write/initialize.js"; import { getDeployedInfraContract } from "./utils/infra.js"; -describe("deployFromMetadata", () => { +// skip this test suite if there is no secret key available to test with +// TODO: remove reliance on secret key during unit tests entirely +describe.skipIf(!process.env.TW_SECRET_KEY)("deployFromMetadata", () => { it("should deploy published contract with existing infra", async () => { const cloneFactoryContract = await getDeployedCloneFactoryContract({ chain: FORKED_ETHEREUM_CHAIN, diff --git a/packages/thirdweb/src/contract/deployment/utils/bootstrap.test.ts b/packages/thirdweb/src/contract/deployment/utils/bootstrap.test.ts index bef2f0adff1..bd945e0e8f1 100644 --- a/packages/thirdweb/src/contract/deployment/utils/bootstrap.test.ts +++ b/packages/thirdweb/src/contract/deployment/utils/bootstrap.test.ts @@ -7,7 +7,9 @@ import { getDeployedCreate2Factory } from "./create-2-factory.js"; import { getDeployedInfraContract } from "./infra.js"; import { fail } from "assert"; -describe("bootstrap", () => { +// skip this test suite if there is no secret key available to test with +// TODO: remove reliance on secret key during unit tests entirely +describe.skipIf(!process.env.TW_SECRET_KEY)("bootstrap", () => { it("should bootstrap onchain infra", async () => { await deployCloneFactory({ chain: ANVIL_CHAIN, diff --git a/packages/thirdweb/src/event/actions/get-events.test.ts b/packages/thirdweb/src/event/actions/get-events.test.ts index 2b0e98d2aec..bce8c81f6c6 100644 --- a/packages/thirdweb/src/event/actions/get-events.test.ts +++ b/packages/thirdweb/src/event/actions/get-events.test.ts @@ -7,7 +7,9 @@ import { import { transferEvent } from "../../extensions/erc721/__generated__/IERC721A/events/Transfer.js"; import { prepareEvent } from "../prepare-event.js"; -describe("getEvents", () => { +// skip this test suite if there is no secret key available to test with +// TODO: remove reliance on secret key during unit tests entirely +describe.skipIf(!process.env.TW_SECRET_KEY)("getEvents", () => { it("should get all events", async () => { const events = await getContractEvents({ contract: USDC_CONTRACT, diff --git a/packages/thirdweb/src/extensions/prebuilts/deploy-erc1155.test.ts b/packages/thirdweb/src/extensions/prebuilts/deploy-erc1155.test.ts index 3fecb4d1a31..84e36d3dc69 100644 --- a/packages/thirdweb/src/extensions/prebuilts/deploy-erc1155.test.ts +++ b/packages/thirdweb/src/extensions/prebuilts/deploy-erc1155.test.ts @@ -6,53 +6,49 @@ import { deployERC1155Contract } from "./deploy-erc1155.js"; import { name } from "../common/read/name.js"; import { getContract } from "../../contract/contract.js"; -describe( - "deployERC1155", - { - retry: 0, - }, - () => { - it("should deploy ERC1155 drop", async () => { - const address = await deployERC1155Contract({ +// skip this test suite if there is no secret key available to test with +// TODO: remove reliance on secret key during unit tests entirely +describe.skipIf(!process.env.TW_SECRET_KEY)("deployERC1155", () => { + it("should deploy ERC1155 drop", async () => { + const address = await deployERC1155Contract({ + client: TEST_CLIENT, + chain: ANVIL_CHAIN, + account: TEST_ACCOUNT_A, + type: "DropERC1155", + params: { + name: "EditionDrop", + symbol: "NFTD", + }, + }); + expect(address).toBe("0xd91A47278829a0128D7212225FE74BC153A7FAF8"); + const deployedName = await name({ + contract: getContract({ client: TEST_CLIENT, chain: ANVIL_CHAIN, - account: TEST_ACCOUNT_A, - type: "DropERC1155", - params: { - name: "EditionDrop", - symbol: "NFTD", - }, - }); - expect(address).toBe("0xd91A47278829a0128D7212225FE74BC153A7FAF8"); - const deployedName = await name({ - contract: getContract({ - client: TEST_CLIENT, - chain: ANVIL_CHAIN, - address, - }), - }); - expect(deployedName).toBe("EditionDrop"); + address, + }), }); + expect(deployedName).toBe("EditionDrop"); + }); - it("should deploy ERC1155 token", async () => { - const address = await deployERC1155Contract({ + it("should deploy ERC1155 token", async () => { + const address = await deployERC1155Contract({ + client: TEST_CLIENT, + chain: ANVIL_CHAIN, + account: TEST_ACCOUNT_A, + type: "TokenERC1155", + params: { + name: "Edition", + }, + }); + expect(address).toBe("0x7dD915A335Af52698bFFFE14D1D3F0DCfdC0a8E6"); + const deployedName = await name({ + contract: getContract({ client: TEST_CLIENT, chain: ANVIL_CHAIN, - account: TEST_ACCOUNT_A, - type: "TokenERC1155", - params: { - name: "Edition", - }, - }); - expect(address).toBe("0x7dD915A335Af52698bFFFE14D1D3F0DCfdC0a8E6"); - const deployedName = await name({ - contract: getContract({ - client: TEST_CLIENT, - chain: ANVIL_CHAIN, - address, - }), - }); - expect(deployedName).toBe("Edition"); + address, + }), }); - }, -); + expect(deployedName).toBe("Edition"); + }); +}); diff --git a/packages/thirdweb/src/extensions/prebuilts/deploy-erc20.test.ts b/packages/thirdweb/src/extensions/prebuilts/deploy-erc20.test.ts index 3078c44e9b7..18897e8f329 100644 --- a/packages/thirdweb/src/extensions/prebuilts/deploy-erc20.test.ts +++ b/packages/thirdweb/src/extensions/prebuilts/deploy-erc20.test.ts @@ -6,53 +6,49 @@ import { deployERC20Contract } from "./deploy-erc20.js"; import { name } from "../common/read/name.js"; import { getContract } from "../../contract/contract.js"; -describe( - "deployERC20", - { - retry: 0, - }, - () => { - it("should deploy ERC20 drop", async () => { - const address = await deployERC20Contract({ +// skip this test suite if there is no secret key available to test with +// TODO: remove reliance on secret key during unit tests entirely +describe.skipIf(!process.env.TW_SECRET_KEY)("deployERC20", () => { + it("should deploy ERC20 drop", async () => { + const address = await deployERC20Contract({ + client: TEST_CLIENT, + chain: ANVIL_CHAIN, + account: TEST_ACCOUNT_A, + type: "DropERC20", + params: { + name: "TokenDrop", + symbol: "NFTD", + }, + }); + expect(address).toBe("0x61Ae22E7240C7e5853749AF49f2552CB8D7C3e35"); + const deployedName = await name({ + contract: getContract({ client: TEST_CLIENT, chain: ANVIL_CHAIN, - account: TEST_ACCOUNT_A, - type: "DropERC20", - params: { - name: "TokenDrop", - symbol: "NFTD", - }, - }); - expect(address).toBe("0x61Ae22E7240C7e5853749AF49f2552CB8D7C3e35"); - const deployedName = await name({ - contract: getContract({ - client: TEST_CLIENT, - chain: ANVIL_CHAIN, - address, - }), - }); - expect(deployedName).toBe("TokenDrop"); + address, + }), }); + expect(deployedName).toBe("TokenDrop"); + }); - it("should deploy ERC20 token", async () => { - const address = await deployERC20Contract({ + it("should deploy ERC20 token", async () => { + const address = await deployERC20Contract({ + client: TEST_CLIENT, + chain: ANVIL_CHAIN, + account: TEST_ACCOUNT_A, + type: "TokenERC20", + params: { + name: "Token", + }, + }); + expect(address).toBe("0x3E8437C96275E9873b0379c1e5d5F0998A9546e9"); + const deployedName = await name({ + contract: getContract({ client: TEST_CLIENT, chain: ANVIL_CHAIN, - account: TEST_ACCOUNT_A, - type: "TokenERC20", - params: { - name: "Token", - }, - }); - expect(address).toBe("0x3E8437C96275E9873b0379c1e5d5F0998A9546e9"); - const deployedName = await name({ - contract: getContract({ - client: TEST_CLIENT, - chain: ANVIL_CHAIN, - address, - }), - }); - expect(deployedName).toBe("Token"); + address, + }), }); - }, -); + expect(deployedName).toBe("Token"); + }); +}); diff --git a/packages/thirdweb/src/extensions/prebuilts/deploy-erc721.test.ts b/packages/thirdweb/src/extensions/prebuilts/deploy-erc721.test.ts index 04d602ed060..19bad8c7e61 100644 --- a/packages/thirdweb/src/extensions/prebuilts/deploy-erc721.test.ts +++ b/packages/thirdweb/src/extensions/prebuilts/deploy-erc721.test.ts @@ -6,73 +6,69 @@ import { deployERC721Contract } from "./deploy-erc721.js"; import { getContract } from "../../contract/contract.js"; import { name } from "../common/read/name.js"; -describe( - "deployERC721", - { - retry: 0, - }, - () => { - it("should deploy ERC721 drop", async () => { - const address = await deployERC721Contract({ +// skip this test suite if there is no secret key available to test with +// TODO: remove reliance on secret key during unit tests entirely +describe.skipIf(!process.env.TW_SECRET_KEY)("deployERC721", () => { + it("should deploy ERC721 drop", async () => { + const address = await deployERC721Contract({ + client: TEST_CLIENT, + chain: ANVIL_CHAIN, + account: TEST_ACCOUNT_A, + type: "DropERC721", + params: { + name: "NFTDrop", + }, + }); + expect(address).toBe("0x6AA2E0148a57EcDdb025C856c4e68682CFfcac78"); + const deployedName = await name({ + contract: getContract({ client: TEST_CLIENT, chain: ANVIL_CHAIN, - account: TEST_ACCOUNT_A, - type: "DropERC721", - params: { - name: "NFTDrop", - }, - }); - expect(address).toBe("0x6AA2E0148a57EcDdb025C856c4e68682CFfcac78"); - const deployedName = await name({ - contract: getContract({ - client: TEST_CLIENT, - chain: ANVIL_CHAIN, - address, - }), - }); - expect(deployedName).toBe("NFTDrop"); + address, + }), }); + expect(deployedName).toBe("NFTDrop"); + }); - it("should deploy ERC721 token", async () => { - const address = await deployERC721Contract({ + it("should deploy ERC721 token", async () => { + const address = await deployERC721Contract({ + client: TEST_CLIENT, + chain: ANVIL_CHAIN, + account: TEST_ACCOUNT_A, + type: "TokenERC721", + params: { + name: "NFTCollection", + }, + }); + expect(address).toBe("0x349D9e8751C40Be121a862FaC1Dc7c357281846E"); + const deployedName = await name({ + contract: getContract({ client: TEST_CLIENT, chain: ANVIL_CHAIN, - account: TEST_ACCOUNT_A, - type: "TokenERC721", - params: { - name: "NFTCollection", - }, - }); - expect(address).toBe("0x349D9e8751C40Be121a862FaC1Dc7c357281846E"); - const deployedName = await name({ - contract: getContract({ - client: TEST_CLIENT, - chain: ANVIL_CHAIN, - address, - }), - }); - expect(deployedName).toBe("NFTCollection"); + address, + }), }); + expect(deployedName).toBe("NFTCollection"); + }); - it("should deploy ERC721 open edition", async () => { - const address = await deployERC721Contract({ + it("should deploy ERC721 open edition", async () => { + const address = await deployERC721Contract({ + client: TEST_CLIENT, + chain: ANVIL_CHAIN, + account: TEST_ACCOUNT_A, + type: "OpenEditionERC721", + params: { + name: "OE", + }, + }); + expect(address).toBe("0x5804ebCE1834B8F57D31f0078B8f7Dd1F1Da4985"); + const deployedName = await name({ + contract: getContract({ client: TEST_CLIENT, chain: ANVIL_CHAIN, - account: TEST_ACCOUNT_A, - type: "OpenEditionERC721", - params: { - name: "OE", - }, - }); - expect(address).toBe("0x5804ebCE1834B8F57D31f0078B8f7Dd1F1Da4985"); - const deployedName = await name({ - contract: getContract({ - client: TEST_CLIENT, - chain: ANVIL_CHAIN, - address, - }), - }); - expect(deployedName).toBe("OE"); + address, + }), }); - }, -); + expect(deployedName).toBe("OE"); + }); +}); diff --git a/packages/thirdweb/src/transaction/actions/send-and-confirm-transaction.test.ts b/packages/thirdweb/src/transaction/actions/send-and-confirm-transaction.test.ts index a1087e7f263..f1356cfb8e8 100644 --- a/packages/thirdweb/src/transaction/actions/send-and-confirm-transaction.test.ts +++ b/packages/thirdweb/src/transaction/actions/send-and-confirm-transaction.test.ts @@ -57,7 +57,9 @@ vi.spyOn(waitForReceiptExports, "waitForReceipt").mockResolvedValueOnce( MOCK_SUCCESS_RECEIPT, ); -describe("sendAndConfirmTransaction", () => { +// skip this test suite if there is no secret key available to test with +// TODO: remove reliance on secret key during unit tests entirely +describe.skipIf(!process.env.TW_SECRET_KEY)("sendAndConfirmTransaction", () => { afterAll(() => { vi.restoreAllMocks(); }); diff --git a/packages/thirdweb/src/transaction/prepare-transaction.test.ts b/packages/thirdweb/src/transaction/prepare-transaction.test.ts index 23c8806718a..88c5f98f757 100644 --- a/packages/thirdweb/src/transaction/prepare-transaction.test.ts +++ b/packages/thirdweb/src/transaction/prepare-transaction.test.ts @@ -1,4 +1,4 @@ -import { describe, test, expect } from "vitest"; +import { describe, test as it, expect } from "vitest"; import { TEST_CLIENT } from "../../test/src/test-clients.js"; import { TEST_WALLET_A, TEST_WALLET_B } from "../../test/src/addresses.js"; @@ -9,7 +9,7 @@ import { ethereum } from "../chains/chain-definitions/ethereum.js"; import { toWei } from "../utils/units.js"; describe("prepareTransaction", () => { - test("should prepare a transaction", () => { + it("should prepare a transaction", () => { const preparedTx = prepareTransaction({ chain: ethereum, client: TEST_CLIENT, @@ -20,19 +20,24 @@ describe("prepareTransaction", () => { expect(preparedTx.value).toMatchInlineSnapshot(`100000000000000000n`); }); - test("should estimate the gas correctly", async () => { - const preparedTx = prepareTransaction({ - chain: ethereum, - client: TEST_CLIENT, - to: TEST_WALLET_B, - value: toWei("0.1"), - }); - const estimate = await estimateGas({ - transaction: preparedTx, - from: TEST_WALLET_A, - }); - // TODO: figure out why this is not `21000n`? - // - a raw transfer SHOULD be 21000gwei always? - expect(estimate).toMatchInlineSnapshot(`21060n`); - }); + // skip this test if there is no secret key available to test with + // TODO: remove reliance on secret key during unit tests entirely + it.skipIf(!process.env.TW_SECRET_KEY)( + "should estimate the gas correctly", + async () => { + const preparedTx = prepareTransaction({ + chain: ethereum, + client: TEST_CLIENT, + to: TEST_WALLET_B, + value: toWei("0.1"), + }); + const estimate = await estimateGas({ + transaction: preparedTx, + from: TEST_WALLET_A, + }); + // TODO: figure out why this is not `21000n`? + // - a raw transfer SHOULD be 21000gwei always? + expect(estimate).toMatchInlineSnapshot(`21060n`); + }, + ); }); diff --git a/packages/thirdweb/src/utils/bytecode/extractIPFS.test.ts b/packages/thirdweb/src/utils/bytecode/extractIPFS.test.ts index d7b9d98ccf7..9cdc30e226c 100644 --- a/packages/thirdweb/src/utils/bytecode/extractIPFS.test.ts +++ b/packages/thirdweb/src/utils/bytecode/extractIPFS.test.ts @@ -6,7 +6,9 @@ import { import { extractIPFSUri } from "./extractIPFS.js"; import { getBytecode } from "../../contract/actions/get-bytecode.js"; -describe("extractIPFSUri", () => { +// skip this test suite if there is no secret key available to test with +// TODO: remove reliance on secret key during unit tests entirely +describe.skipIf(!process.env.TW_SECRET_KEY)("extractIPFSUri", () => { it("works if ipfs is there", async () => { // get some bytecode const bytecode = await getBytecode(DOODLES_CONTRACT); @@ -28,11 +30,4 @@ describe("extractIPFSUri", () => { // USDC bytecode does not contain an IPFS hash expect(ipfsHash).toMatchInlineSnapshot(`undefined`); }); - - it("works with the weird mumbai contract", async () => { - const ipfsHash = extractIPFSUri( - "0x363d3d373d3d3d363d30545af43d82803e903d91601857fd5bf3", - ); - expect(ipfsHash).toMatchInlineSnapshot(`undefined`); - }); }); diff --git a/turbo.json b/turbo.json index fd9190bdc76..cf419ac9a80 100644 --- a/turbo.json +++ b/turbo.json @@ -142,5 +142,5 @@ "dependsOn": ["build"] } }, - "globalEnv": ["CI"] + "globalEnv": ["CI", "TW_SECRET_KEY"] } From cde04d568d40b69e309ec6b84350fdb28c29dfcf Mon Sep 17 00:00:00 2001 From: Jonas Daniels Date: Sat, 30 Mar 2024 16:25:54 -0700 Subject: [PATCH 3/6] test: update test descriptions for erc1155 and erc721 getNFT --- .../thirdweb/src/extensions/erc1155/read/getNFT.test.ts | 4 ++-- packages/thirdweb/src/extensions/erc721/read/getNFT.test.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/thirdweb/src/extensions/erc1155/read/getNFT.test.ts b/packages/thirdweb/src/extensions/erc1155/read/getNFT.test.ts index ab5936f480f..39dd0765a92 100644 --- a/packages/thirdweb/src/extensions/erc1155/read/getNFT.test.ts +++ b/packages/thirdweb/src/extensions/erc1155/read/getNFT.test.ts @@ -3,8 +3,8 @@ import { describe, it, expect } from "vitest"; import { getNFT } from "./getNFT.js"; import { DROP1155_CONTRACT } from "~test/test-contracts.js"; -describe("erc1155.getNFT", () => { - it.runIf(process.env.TW_SECRET_KEY)("without owner", async () => { +describe.runIf(process.env.TW_SECRET_KEY)("erc1155.getNFT", () => { + it("without owner", async () => { const nft = await getNFT({ contract: DROP1155_CONTRACT, tokenId: 2n, diff --git a/packages/thirdweb/src/extensions/erc721/read/getNFT.test.ts b/packages/thirdweb/src/extensions/erc721/read/getNFT.test.ts index 95cca6d1463..d1126d3baf8 100644 --- a/packages/thirdweb/src/extensions/erc721/read/getNFT.test.ts +++ b/packages/thirdweb/src/extensions/erc721/read/getNFT.test.ts @@ -3,8 +3,8 @@ import { describe, it, expect } from "vitest"; import { getNFT } from "./getNFT.js"; import { DOODLES_CONTRACT } from "~test/test-contracts.js"; -describe("erc721.getNFT", () => { - it.runIf(process.env.TW_SECRET_KEY)("without owner", async () => { +describe.runIf(process.env.TW_SECRET_KEY)("erc721.getNFT", () => { + it("without owner", async () => { const nft = await getNFT({ contract: { ...DOODLES_CONTRACT }, tokenId: 1n, @@ -47,7 +47,7 @@ describe("erc721.getNFT", () => { `); }); - it.runIf(process.env.TW_SECRET_KEY)("with owner", async () => { + it("with owner", async () => { const nft = await getNFT({ contract: { ...DOODLES_CONTRACT }, tokenId: 1n, From 31d014cf8701686dd9b8d5f2e641a9769388bfac Mon Sep 17 00:00:00 2001 From: Jonas Daniels Date: Sat, 30 Mar 2024 16:42:21 -0700 Subject: [PATCH 4/6] refactor(test): update test descriptions and conditions --- .../deployment/deploy-via-autofactory.test.ts | 2 +- .../deployment/utils/bootstrap.test.ts | 2 +- .../src/event/actions/get-events.test.ts | 2 +- .../src/extensions/ens/resolve-address.test.ts | 4 +++- .../extensions/erc721/write/sigMint.test.ts | 4 +++- .../prebuilts/deploy-erc1155.test.ts | 2 +- .../extensions/prebuilts/deploy-erc20.test.ts | 2 +- .../extensions/prebuilts/deploy-erc721.test.ts | 2 +- .../send-and-confirm-transaction.test.ts | 2 +- .../transaction/prepare-transaction.test.ts | 2 +- .../utils/any-evm/is-eip155-enforced.test.ts | 4 +++- .../src/utils/bytecode/extractIPFS.test.ts | 2 +- packages/thirdweb/test/globalSetup.ts | 18 ++++++++---------- 13 files changed, 26 insertions(+), 22 deletions(-) diff --git a/packages/thirdweb/src/contract/deployment/deploy-via-autofactory.test.ts b/packages/thirdweb/src/contract/deployment/deploy-via-autofactory.test.ts index 1ee44f86c60..9b0690aa24c 100644 --- a/packages/thirdweb/src/contract/deployment/deploy-via-autofactory.test.ts +++ b/packages/thirdweb/src/contract/deployment/deploy-via-autofactory.test.ts @@ -14,7 +14,7 @@ import { getDeployedInfraContract } from "./utils/infra.js"; // skip this test suite if there is no secret key available to test with // TODO: remove reliance on secret key during unit tests entirely -describe.skipIf(!process.env.TW_SECRET_KEY)("deployFromMetadata", () => { +describe.runIf(process.env.TW_SECRET_KEY)("deployFromMetadata", () => { it("should deploy published contract with existing infra", async () => { const cloneFactoryContract = await getDeployedCloneFactoryContract({ chain: FORKED_ETHEREUM_CHAIN, diff --git a/packages/thirdweb/src/contract/deployment/utils/bootstrap.test.ts b/packages/thirdweb/src/contract/deployment/utils/bootstrap.test.ts index bd945e0e8f1..b7c96deeee0 100644 --- a/packages/thirdweb/src/contract/deployment/utils/bootstrap.test.ts +++ b/packages/thirdweb/src/contract/deployment/utils/bootstrap.test.ts @@ -9,7 +9,7 @@ import { fail } from "assert"; // skip this test suite if there is no secret key available to test with // TODO: remove reliance on secret key during unit tests entirely -describe.skipIf(!process.env.TW_SECRET_KEY)("bootstrap", () => { +describe.runIf(process.env.TW_SECRET_KEY)("bootstrap", () => { it("should bootstrap onchain infra", async () => { await deployCloneFactory({ chain: ANVIL_CHAIN, diff --git a/packages/thirdweb/src/event/actions/get-events.test.ts b/packages/thirdweb/src/event/actions/get-events.test.ts index bce8c81f6c6..102f37f05ba 100644 --- a/packages/thirdweb/src/event/actions/get-events.test.ts +++ b/packages/thirdweb/src/event/actions/get-events.test.ts @@ -9,7 +9,7 @@ import { prepareEvent } from "../prepare-event.js"; // skip this test suite if there is no secret key available to test with // TODO: remove reliance on secret key during unit tests entirely -describe.skipIf(!process.env.TW_SECRET_KEY)("getEvents", () => { +describe.runIf(process.env.TW_SECRET_KEY)("getEvents", () => { it("should get all events", async () => { const events = await getContractEvents({ contract: USDC_CONTRACT, diff --git a/packages/thirdweb/src/extensions/ens/resolve-address.test.ts b/packages/thirdweb/src/extensions/ens/resolve-address.test.ts index aeb93165f6f..db12d4686d7 100644 --- a/packages/thirdweb/src/extensions/ens/resolve-address.test.ts +++ b/packages/thirdweb/src/extensions/ens/resolve-address.test.ts @@ -2,7 +2,9 @@ import { describe, it, expect } from "vitest"; import { resolveAddress } from "./resolve-address.js"; import { TEST_CLIENT } from "../../../test/src/test-clients.js"; -describe("ENS", () => { +// skip this test suite if there is no secret key available to test with +// TODO: remove reliance on secret key during unit tests entirely +describe.runIf(process.env.TW_SECRET_KEY)("ENS", () => { it("should resolve ENS", async () => { const name = "vitalik.eth"; const address = await resolveAddress({ diff --git a/packages/thirdweb/src/extensions/erc721/write/sigMint.test.ts b/packages/thirdweb/src/extensions/erc721/write/sigMint.test.ts index 0c73e011045..f6273a92173 100644 --- a/packages/thirdweb/src/extensions/erc721/write/sigMint.test.ts +++ b/packages/thirdweb/src/extensions/erc721/write/sigMint.test.ts @@ -16,7 +16,9 @@ import { USDC_CONTRACT_ADDRESS } from "../../../../test/src/test-contracts.js"; import { toHex } from "../../../utils/encoding/hex.js"; import { sendTransaction } from "../../../transaction/actions/send-transaction.js"; -describe( +// skip this test suite if there is no secret key available to test with +// TODO: remove reliance on secret key during unit tests entirely +describe.runIf(process.env.TW_SECRET_KEY)( "generateMintSignature", { timeout: 60000, diff --git a/packages/thirdweb/src/extensions/prebuilts/deploy-erc1155.test.ts b/packages/thirdweb/src/extensions/prebuilts/deploy-erc1155.test.ts index 84e36d3dc69..d8297f10696 100644 --- a/packages/thirdweb/src/extensions/prebuilts/deploy-erc1155.test.ts +++ b/packages/thirdweb/src/extensions/prebuilts/deploy-erc1155.test.ts @@ -8,7 +8,7 @@ import { getContract } from "../../contract/contract.js"; // skip this test suite if there is no secret key available to test with // TODO: remove reliance on secret key during unit tests entirely -describe.skipIf(!process.env.TW_SECRET_KEY)("deployERC1155", () => { +describe.runIf(process.env.TW_SECRET_KEY)("deployERC1155", () => { it("should deploy ERC1155 drop", async () => { const address = await deployERC1155Contract({ client: TEST_CLIENT, diff --git a/packages/thirdweb/src/extensions/prebuilts/deploy-erc20.test.ts b/packages/thirdweb/src/extensions/prebuilts/deploy-erc20.test.ts index 18897e8f329..a02bfcc681a 100644 --- a/packages/thirdweb/src/extensions/prebuilts/deploy-erc20.test.ts +++ b/packages/thirdweb/src/extensions/prebuilts/deploy-erc20.test.ts @@ -8,7 +8,7 @@ import { getContract } from "../../contract/contract.js"; // skip this test suite if there is no secret key available to test with // TODO: remove reliance on secret key during unit tests entirely -describe.skipIf(!process.env.TW_SECRET_KEY)("deployERC20", () => { +describe.runIf(process.env.TW_SECRET_KEY)("deployERC20", () => { it("should deploy ERC20 drop", async () => { const address = await deployERC20Contract({ client: TEST_CLIENT, diff --git a/packages/thirdweb/src/extensions/prebuilts/deploy-erc721.test.ts b/packages/thirdweb/src/extensions/prebuilts/deploy-erc721.test.ts index 19bad8c7e61..4d64de21671 100644 --- a/packages/thirdweb/src/extensions/prebuilts/deploy-erc721.test.ts +++ b/packages/thirdweb/src/extensions/prebuilts/deploy-erc721.test.ts @@ -8,7 +8,7 @@ import { name } from "../common/read/name.js"; // skip this test suite if there is no secret key available to test with // TODO: remove reliance on secret key during unit tests entirely -describe.skipIf(!process.env.TW_SECRET_KEY)("deployERC721", () => { +describe.runIf(process.env.TW_SECRET_KEY)("deployERC721", () => { it("should deploy ERC721 drop", async () => { const address = await deployERC721Contract({ client: TEST_CLIENT, diff --git a/packages/thirdweb/src/transaction/actions/send-and-confirm-transaction.test.ts b/packages/thirdweb/src/transaction/actions/send-and-confirm-transaction.test.ts index f1356cfb8e8..7b48277ef70 100644 --- a/packages/thirdweb/src/transaction/actions/send-and-confirm-transaction.test.ts +++ b/packages/thirdweb/src/transaction/actions/send-and-confirm-transaction.test.ts @@ -59,7 +59,7 @@ vi.spyOn(waitForReceiptExports, "waitForReceipt").mockResolvedValueOnce( // skip this test suite if there is no secret key available to test with // TODO: remove reliance on secret key during unit tests entirely -describe.skipIf(!process.env.TW_SECRET_KEY)("sendAndConfirmTransaction", () => { +describe.runIf(process.env.TW_SECRET_KEY)("sendAndConfirmTransaction", () => { afterAll(() => { vi.restoreAllMocks(); }); diff --git a/packages/thirdweb/src/transaction/prepare-transaction.test.ts b/packages/thirdweb/src/transaction/prepare-transaction.test.ts index 88c5f98f757..c8f679d2f21 100644 --- a/packages/thirdweb/src/transaction/prepare-transaction.test.ts +++ b/packages/thirdweb/src/transaction/prepare-transaction.test.ts @@ -22,7 +22,7 @@ describe("prepareTransaction", () => { // skip this test if there is no secret key available to test with // TODO: remove reliance on secret key during unit tests entirely - it.skipIf(!process.env.TW_SECRET_KEY)( + it.runIf(process.env.TW_SECRET_KEY)( "should estimate the gas correctly", async () => { const preparedTx = prepareTransaction({ diff --git a/packages/thirdweb/src/utils/any-evm/is-eip155-enforced.test.ts b/packages/thirdweb/src/utils/any-evm/is-eip155-enforced.test.ts index 599e042f5bf..83d076e961c 100644 --- a/packages/thirdweb/src/utils/any-evm/is-eip155-enforced.test.ts +++ b/packages/thirdweb/src/utils/any-evm/is-eip155-enforced.test.ts @@ -4,7 +4,9 @@ import { TEST_CLIENT } from "../../../test/src/test-clients.js"; import { optimism } from "../../chains/chain-definitions/optimism.js"; import { ethereum } from "../../chains/chain-definitions/ethereum.js"; -describe("isEIP155Enforced", () => { +// skip this test suite if there is no secret key available to test with +// TODO: remove reliance on secret key during unit tests entirely +describe.runIf(process.env.TW_SECRET_KEY)("isEIP155Enforced", () => { it("should return true if EIP-155 is enforced", async () => { // Call the isEIP155Enforced function with a chain that enforces EIP-155 const result = await isEIP155Enforced({ diff --git a/packages/thirdweb/src/utils/bytecode/extractIPFS.test.ts b/packages/thirdweb/src/utils/bytecode/extractIPFS.test.ts index 9cdc30e226c..40840dfd039 100644 --- a/packages/thirdweb/src/utils/bytecode/extractIPFS.test.ts +++ b/packages/thirdweb/src/utils/bytecode/extractIPFS.test.ts @@ -8,7 +8,7 @@ import { getBytecode } from "../../contract/actions/get-bytecode.js"; // skip this test suite if there is no secret key available to test with // TODO: remove reliance on secret key during unit tests entirely -describe.skipIf(!process.env.TW_SECRET_KEY)("extractIPFSUri", () => { +describe.runIf(process.env.TW_SECRET_KEY)("extractIPFSUri", () => { it("works if ipfs is there", async () => { // get some bytecode const bytecode = await getBytecode(DOODLES_CONTRACT); diff --git a/packages/thirdweb/test/globalSetup.ts b/packages/thirdweb/test/globalSetup.ts index d09598a281d..92e928dc38b 100644 --- a/packages/thirdweb/test/globalSetup.ts +++ b/packages/thirdweb/test/globalSetup.ts @@ -1,4 +1,3 @@ -import { sha256 } from "@noble/hashes/sha256"; import { startProxy } from "@viem/anvil"; import { FORK_BLOCK_NUMBER, OPTIMISM_FORK_BLOCK_NUMBER } from "./src/chains.js"; @@ -7,18 +6,15 @@ require("dotenv-mono").load(); const SECRET_KEY = process.env.TW_SECRET_KEY as string; -const clientId = SECRET_KEY - ? // eslint-disable-next-line no-restricted-globals - Buffer.from(sha256(SECRET_KEY)).toString("hex").slice(0, 32) - : ""; - export default async function globalSetup() { const shutdownMainnet = await startProxy({ port: 8645, options: { chainId: 1, - forkUrl: `https://1.rpc.thirdweb.com/${clientId}`, - forkHeader: { "x-secret-key": SECRET_KEY }, + forkUrl: SECRET_KEY + ? `https://1.rpc.thirdweb.com/` + : "https://cloudflare-eth.com/", + forkHeader: SECRET_KEY ? { "x-secret-key": SECRET_KEY } : {}, forkChainId: 1, forkBlockNumber: FORK_BLOCK_NUMBER, noMining: true, @@ -30,8 +26,10 @@ export default async function globalSetup() { port: 8646, options: { chainId: 10, - forkUrl: `https://10.rpc.thirdweb.com/${clientId}`, - forkHeader: { "x-secret-key": SECRET_KEY }, + forkUrl: SECRET_KEY + ? `https://10.rpc.thirdweb.com/` + : "https://mainnet.optimism.io/", + forkHeader: SECRET_KEY ? { "x-secret-key": SECRET_KEY } : {}, forkChainId: 10, forkBlockNumber: OPTIMISM_FORK_BLOCK_NUMBER, noMining: true, From 2a44632b19437574e1479f1bcf3eaa1700f402d2 Mon Sep 17 00:00:00 2001 From: Jonas Daniels Date: Sat, 30 Mar 2024 16:49:41 -0700 Subject: [PATCH 5/6] test(chore): update test client configuration --- .../thirdweb/src/extensions/erc1155/read/getNFT.test.ts | 2 +- .../src/extensions/erc721/read/getAllOwners.test.ts | 2 +- .../thirdweb/src/extensions/erc721/read/getNFT.test.ts | 2 +- .../thirdweb/src/extensions/erc721/read/getNFTs.test.ts | 2 +- packages/thirdweb/test/src/test-clients.ts | 8 +++++++- 5 files changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/thirdweb/src/extensions/erc1155/read/getNFT.test.ts b/packages/thirdweb/src/extensions/erc1155/read/getNFT.test.ts index 39dd0765a92..61446079d6a 100644 --- a/packages/thirdweb/src/extensions/erc1155/read/getNFT.test.ts +++ b/packages/thirdweb/src/extensions/erc1155/read/getNFT.test.ts @@ -3,7 +3,7 @@ import { describe, it, expect } from "vitest"; import { getNFT } from "./getNFT.js"; import { DROP1155_CONTRACT } from "~test/test-contracts.js"; -describe.runIf(process.env.TW_SECRET_KEY)("erc1155.getNFT", () => { +describe("erc1155.getNFT", () => { it("without owner", async () => { const nft = await getNFT({ contract: DROP1155_CONTRACT, diff --git a/packages/thirdweb/src/extensions/erc721/read/getAllOwners.test.ts b/packages/thirdweb/src/extensions/erc721/read/getAllOwners.test.ts index 92b99efc299..4cb94758c24 100644 --- a/packages/thirdweb/src/extensions/erc721/read/getAllOwners.test.ts +++ b/packages/thirdweb/src/extensions/erc721/read/getAllOwners.test.ts @@ -3,7 +3,7 @@ import { describe, it, expect } from "vitest"; import { getAllOwners } from "./getAllOwners.js"; import { AZUKI_CONTRACT, DOODLES_CONTRACT } from "~test/test-contracts.js"; -describe.runIf(process.env.TW_SECRET_KEY)("erc721.getAllOwners", () => { +describe("erc721.getAllOwners", () => { it("works for azuki", async () => { const nfts = await getAllOwners({ contract: AZUKI_CONTRACT, diff --git a/packages/thirdweb/src/extensions/erc721/read/getNFT.test.ts b/packages/thirdweb/src/extensions/erc721/read/getNFT.test.ts index d1126d3baf8..5a9f44ddfd0 100644 --- a/packages/thirdweb/src/extensions/erc721/read/getNFT.test.ts +++ b/packages/thirdweb/src/extensions/erc721/read/getNFT.test.ts @@ -3,7 +3,7 @@ import { describe, it, expect } from "vitest"; import { getNFT } from "./getNFT.js"; import { DOODLES_CONTRACT } from "~test/test-contracts.js"; -describe.runIf(process.env.TW_SECRET_KEY)("erc721.getNFT", () => { +describe("erc721.getNFT", () => { it("without owner", async () => { const nft = await getNFT({ contract: { ...DOODLES_CONTRACT }, diff --git a/packages/thirdweb/src/extensions/erc721/read/getNFTs.test.ts b/packages/thirdweb/src/extensions/erc721/read/getNFTs.test.ts index c303afc1b29..58a5142afaa 100644 --- a/packages/thirdweb/src/extensions/erc721/read/getNFTs.test.ts +++ b/packages/thirdweb/src/extensions/erc721/read/getNFTs.test.ts @@ -3,7 +3,7 @@ import { describe, it, expect } from "vitest"; import { getNFTs } from "./getNFTs.js"; import { AZUKI_CONTRACT, DOODLES_CONTRACT } from "~test/test-contracts.js"; -describe.runIf(process.env.TW_SECRET_KEY)("erc721.getNFTs", () => { +describe("erc721.getNFTs", () => { it("works for azuki", async () => { const nfts = await getNFTs({ contract: AZUKI_CONTRACT, diff --git a/packages/thirdweb/test/src/test-clients.ts b/packages/thirdweb/test/src/test-clients.ts index ffdab6547f2..830f08bc837 100644 --- a/packages/thirdweb/test/src/test-clients.ts +++ b/packages/thirdweb/test/src/test-clients.ts @@ -3,5 +3,11 @@ import { createThirdwebClient } from "../../src/client/client.js"; const secretKey = process.env.TW_SECRET_KEY; export const TEST_CLIENT = createThirdwebClient( - secretKey ? { secretKey } : { clientId: "TEST" }, + secretKey + ? { secretKey } + : { + clientId: "TEST", + // if we don't have a secret key, we can use a public gateway for testing? + config: { storage: { gatewayUrl: "https://cf-ipfs.com" } }, + }, ); From 551c38f8218e0864dc650c050518d098126e49ba Mon Sep 17 00:00:00 2001 From: Jonas Daniels Date: Sat, 30 Mar 2024 16:51:35 -0700 Subject: [PATCH 6/6] feat: Add clientId to forkUrl in globalSetup function --- packages/thirdweb/test/globalSetup.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/thirdweb/test/globalSetup.ts b/packages/thirdweb/test/globalSetup.ts index 92e928dc38b..c97be2dcf42 100644 --- a/packages/thirdweb/test/globalSetup.ts +++ b/packages/thirdweb/test/globalSetup.ts @@ -1,19 +1,25 @@ import { startProxy } from "@viem/anvil"; import { FORK_BLOCK_NUMBER, OPTIMISM_FORK_BLOCK_NUMBER } from "./src/chains.js"; +import { sha256 } from "@noble/hashes/sha256"; // eslint-disable-next-line @typescript-eslint/no-var-requires require("dotenv-mono").load(); const SECRET_KEY = process.env.TW_SECRET_KEY as string; +const clientId = SECRET_KEY + ? // eslint-disable-next-line no-restricted-globals + Buffer.from(sha256(SECRET_KEY)).toString("hex").slice(0, 32) + : ""; + export default async function globalSetup() { const shutdownMainnet = await startProxy({ port: 8645, options: { chainId: 1, forkUrl: SECRET_KEY - ? `https://1.rpc.thirdweb.com/` - : "https://cloudflare-eth.com/", + ? `https://1.rpc.thirdweb.com/${clientId}` + : "https://mainnet.gateway.tenderly.co", forkHeader: SECRET_KEY ? { "x-secret-key": SECRET_KEY } : {}, forkChainId: 1, forkBlockNumber: FORK_BLOCK_NUMBER, @@ -27,7 +33,7 @@ export default async function globalSetup() { options: { chainId: 10, forkUrl: SECRET_KEY - ? `https://10.rpc.thirdweb.com/` + ? `https://10.rpc.thirdweb.com/${clientId}` : "https://mainnet.optimism.io/", forkHeader: SECRET_KEY ? { "x-secret-key": SECRET_KEY } : {}, forkChainId: 10,