diff --git a/script/lint.js b/script/lint.js index a66423bb0f..5e7489ee8d 100755 --- a/script/lint.js +++ b/script/lint.js @@ -16,7 +16,7 @@ const DEPOT_TOOLS = path.resolve(SOURCE_ROOT, 'third_party', 'depot_tools'); const IGNORELIST = new Set([ ['shell', 'browser', 'resources', 'win', 'resource.h'], ['shell', 'common', 'node_includes.h'], - ['spec', 'static', 'jquery-2.0.3.min.js'], + ['spec-main', 'fixtures', 'pages', 'jquery-3.6.0.min.js'], ['spec', 'ts-smoke', 'electron', 'main.ts'], ['spec', 'ts-smoke', 'electron', 'renderer.ts'], ['spec', 'ts-smoke', 'runner.js'] diff --git a/spec-main/.eslintrc b/spec-main/.eslintrc index a26475e27d..60be8a0dac 100644 --- a/spec-main/.eslintrc +++ b/spec-main/.eslintrc @@ -2,7 +2,6 @@ "env": { "browser": true, "mocha": true, - "jquery": true, "serviceworker": true }, "globals": { diff --git a/spec-main/api-protocol-spec.ts b/spec-main/api-protocol-spec.ts index 71437da6fe..980c289cb1 100644 --- a/spec-main/api-protocol-spec.ts +++ b/spec-main/api-protocol-spec.ts @@ -29,7 +29,7 @@ const unregisterProtocol = protocol.unregisterProtocol; const uninterceptProtocol = protocol.uninterceptProtocol; const text = 'valar morghulis'; -const protocolName = 'sp'; +const protocolName = 'no-cors'; const postData = { name: 'post test', type: 'string' @@ -80,7 +80,7 @@ describe('protocol module', () => { // Note that we need to do navigation every time after a protocol is // registered or unregistered, otherwise the new protocol won't be // recognized by current page when NetworkService is used. - await contents.loadFile(path.join(__dirname, 'fixtures', 'pages', 'jquery.html')); + await contents.loadFile(path.join(__dirname, 'fixtures', 'pages', 'fetch.html')); return contents.executeJavaScript(`ajax("${url}", ${JSON.stringify(options)})`); } @@ -110,7 +110,7 @@ describe('protocol module', () => { it('sends error when callback is called with nothing', async () => { registerBufferProtocol(protocolName, (req, cb: any) => cb()); - await expect(ajax(protocolName + '://fake-host')).to.eventually.be.rejectedWith(Error, '404'); + await expect(ajax(protocolName + '://fake-host')).to.eventually.be.rejected(); }); it('does not crash when callback is called in next tick', async () => { @@ -157,7 +157,7 @@ describe('protocol module', () => { registerStringProtocol(protocolName, (request, callback) => callback(text)); const r = await ajax(protocolName + '://fake-host'); expect(r.data).to.equal(text); - expect(r.headers).to.include('access-control-allow-origin: *'); + expect(r.headers).to.have.property('access-control-allow-origin', '*'); }); it('sends object as response', async () => { @@ -174,7 +174,7 @@ describe('protocol module', () => { it('fails when sending object other than string', async () => { const notAString = () => {}; registerStringProtocol(protocolName, (request, callback) => callback(notAString as any)); - await expect(ajax(protocolName + '://fake-host')).to.be.eventually.rejectedWith(Error, '404'); + await expect(ajax(protocolName + '://fake-host')).to.be.eventually.rejected(); }); }); @@ -190,7 +190,7 @@ describe('protocol module', () => { registerBufferProtocol(protocolName, (request, callback) => callback(buffer)); const r = await ajax(protocolName + '://fake-host'); expect(r.data).to.equal(text); - expect(r.headers).to.include('access-control-allow-origin: *'); + expect(r.headers).to.have.property('access-control-allow-origin', '*'); }); it('sends object as response', async () => { @@ -206,7 +206,7 @@ describe('protocol module', () => { it('fails when sending string', async () => { registerBufferProtocol(protocolName, (request, callback) => callback(text as any)); - await expect(ajax(protocolName + '://fake-host')).to.be.eventually.rejectedWith(Error, '404'); + await expect(ajax(protocolName + '://fake-host')).to.be.eventually.rejected(); }); }); @@ -226,7 +226,7 @@ describe('protocol module', () => { registerFileProtocol(protocolName, (request, callback) => callback(filePath)); const r = await ajax(protocolName + '://fake-host'); expect(r.data).to.equal(String(fileContent)); - expect(r.headers).to.include('access-control-allow-origin: *'); + expect(r.headers).to.have.property('access-control-allow-origin', '*'); }); it('sets custom headers', async () => { @@ -236,7 +236,7 @@ describe('protocol module', () => { })); const r = await ajax(protocolName + '://fake-host'); expect(r.data).to.equal(String(fileContent)); - expect(r.headers).to.include('x-great-header: sogreat'); + expect(r.headers).to.have.property('x-great-header', 'sogreat'); }); it.skip('throws an error when custom headers are invalid', (done) => { @@ -247,7 +247,7 @@ describe('protocol module', () => { })).to.throw(Error, 'Value of \'X-Great-Header\' header has to be a string'); done(); }); - ajax(protocolName + '://fake-host'); + ajax(protocolName + '://fake-host').catch(() => {}); }); it('sends object as response', async () => { @@ -265,12 +265,12 @@ describe('protocol module', () => { it('fails when sending unexist-file', async () => { const fakeFilePath = path.join(fixturesPath, 'test.asar', 'a.asar', 'not-exist'); registerFileProtocol(protocolName, (request, callback) => callback(fakeFilePath)); - await expect(ajax(protocolName + '://fake-host')).to.be.eventually.rejectedWith(Error, '404'); + await expect(ajax(protocolName + '://fake-host')).to.be.eventually.rejected(); }); it('fails when sending unsupported content', async () => { registerFileProtocol(protocolName, (request, callback) => callback(new Date() as any)); - await expect(ajax(protocolName + '://fake-host')).to.be.eventually.rejectedWith(Error, '404'); + await expect(ajax(protocolName + '://fake-host')).to.be.eventually.rejected(); }); }); @@ -292,12 +292,12 @@ describe('protocol module', () => { it('fails when sending invalid url', async () => { registerHttpProtocol(protocolName, (request, callback) => callback({ url: 'url' })); - await expect(ajax(protocolName + '://fake-host')).to.be.eventually.rejectedWith(Error, '404'); + await expect(ajax(protocolName + '://fake-host')).to.be.eventually.rejected(); }); it('fails when sending unsupported content', async () => { registerHttpProtocol(protocolName, (request, callback) => callback(new Date() as any)); - await expect(ajax(protocolName + '://fake-host')).to.be.eventually.rejectedWith(Error, '404'); + await expect(ajax(protocolName + '://fake-host')).to.be.eventually.rejected(); }); it('works when target URL redirects', async () => { @@ -331,7 +331,7 @@ describe('protocol module', () => { done(e); } }); - ajax(protocolName + '://fake-host'); + ajax(protocolName + '://fake-host').catch(() => {}); }); }); @@ -359,7 +359,7 @@ describe('protocol module', () => { const r = await ajax(protocolName + '://fake-host'); expect(r.data).to.equal(text); expect(r.status).to.equal(200); - expect(r.headers).to.include('x-electron: a, b'); + expect(r.headers).to.have.property('x-electron', 'a, b'); }); it('sends custom status code', async () => { @@ -368,7 +368,7 @@ describe('protocol module', () => { data: null as any })); const r = await ajax(protocolName + '://fake-host'); - expect(r.data).to.be.undefined('data'); + expect(r.data).to.be.empty('data'); expect(r.status).to.equal(204); }); @@ -382,7 +382,7 @@ describe('protocol module', () => { }); }); const r = await ajax(protocolName + '://fake-host', { headers: { 'x-return-headers': 'yes' } }); - expect(r.data['x-return-headers']).to.equal('yes'); + expect(JSON.parse(r.data)['x-return-headers']).to.equal('yes'); }); it('returns response multiple response headers with the same name', async () => { @@ -399,7 +399,8 @@ describe('protocol module', () => { // SUBTLE: when the response headers have multiple values it // separates values by ", ". When the response headers are incorrectly // converting an array to a string it separates values by ",". - expect(r.headers).to.equal('header1: value1, value2\r\nheader2: value3\r\n'); + expect(r.headers).to.have.property('header1', 'value1, value2'); + expect(r.headers).to.have.property('header2', 'value3'); }); it('can handle large responses', async () => { @@ -456,7 +457,7 @@ describe('protocol module', () => { }); }); const hasEndedPromise = emittedOnce(events, 'end'); - ajax(protocolName + '://fake-host'); + ajax(protocolName + '://fake-host').catch(() => {}); await hasEndedPromise; }); @@ -478,9 +479,9 @@ describe('protocol module', () => { const hasRespondedPromise = emittedOnce(events, 'respond'); const hasClosedPromise = emittedOnce(events, 'close'); - ajax(protocolName + '://fake-host'); + ajax(protocolName + '://fake-host').catch(() => {}); await hasRespondedPromise; - await contents.loadFile(path.join(__dirname, 'fixtures', 'pages', 'jquery.html')); + await contents.loadFile(path.join(__dirname, 'fixtures', 'pages', 'fetch.html')); await hasClosedPromise; }); }); @@ -527,7 +528,7 @@ describe('protocol module', () => { it('sends error when callback is called with nothing', async () => { interceptStringProtocol('http', (request, callback: any) => callback()); - await expect(ajax('http://fake-host')).to.be.eventually.rejectedWith(Error, '404'); + await expect(ajax('http://fake-host')).to.be.eventually.rejected(); }); }); @@ -546,8 +547,7 @@ describe('protocol module', () => { }); }); const r = await ajax('http://fake-host'); - expect(r.data).to.be.an('object'); - expect(r.data).to.have.property('value').that.is.equal(1); + expect(JSON.parse(r.data)).to.have.property('value').that.is.equal(1); }); it('can set content-type with charset', async () => { @@ -558,8 +558,7 @@ describe('protocol module', () => { }); }); const r = await ajax('http://fake-host'); - expect(r.data).to.be.an('object'); - expect(r.data).to.have.property('value').that.is.equal(1); + expect(JSON.parse(r.data)).to.have.property('value').that.is.equal(1); }); it('can receive post data', async () => { @@ -567,7 +566,7 @@ describe('protocol module', () => { const uploadData = request.uploadData![0].bytes.toString(); callback({ data: uploadData }); }); - const r = await ajax('http://fake-host', { type: 'POST', data: postData }); + const r = await ajax('http://fake-host', { method: 'POST', body: qs.stringify(postData) }); expect({ ...qs.parse(r.data) }).to.deep.equal(postData); }); }); @@ -584,8 +583,8 @@ describe('protocol module', () => { const uploadData = request.uploadData![0].bytes; callback(uploadData); }); - const r = await ajax('http://fake-host', { type: 'POST', data: postData }); - expect(r.data).to.equal('name=post+test&type=string'); + const r = await ajax('http://fake-host', { method: 'POST', body: qs.stringify(postData) }); + expect(qs.parse(r.data)).to.deep.equal({ name: 'post test', type: 'string' }); }); }); @@ -651,7 +650,7 @@ describe('protocol module', () => { done(e); } }); - ajax('http://fake-host'); + ajax('http://fake-host').catch(() => {}); }); }); @@ -666,7 +665,7 @@ describe('protocol module', () => { interceptStreamProtocol('http', (request, callback) => { callback(getStream(3, request.uploadData![0].bytes.toString())); }); - const r = await ajax('http://fake-host', { type: 'POST', data: postData }); + const r = await ajax('http://fake-host', { method: 'POST', body: qs.stringify(postData) }); expect({ ...qs.parse(r.data) }).to.deep.equal(postData); }); diff --git a/spec-main/api-web-request-spec.ts b/spec-main/api-web-request-spec.ts index ea088b64fa..f939f4af5a 100644 --- a/spec-main/api-web-request-spec.ts +++ b/spec-main/api-web-request-spec.ts @@ -36,7 +36,7 @@ describe('webRequest module', () => { let defaultURL: string; before((done) => { - protocol.registerStringProtocol('neworigin', (req, cb) => cb('')); + protocol.registerStringProtocol('cors', (req, cb) => cb('')); server.listen(0, '127.0.0.1', () => { const port = (server.address() as AddressInfo).port; defaultURL = `http://127.0.0.1:${port}/`; @@ -46,14 +46,14 @@ describe('webRequest module', () => { after(() => { server.close(); - protocol.unregisterProtocol('neworigin'); + protocol.unregisterProtocol('cors'); }); let contents: WebContents = null as unknown as WebContents; // NB. sandbox: true is used because it makes navigations much (~8x) faster. before(async () => { contents = (webContents as any).create({ sandbox: true }); - await contents.loadFile(path.join(fixturesPath, 'pages', 'jquery.html')); + await contents.loadFile(path.join(fixturesPath, 'pages', 'fetch.html')); }); after(() => (contents as any).destroy()); @@ -72,7 +72,7 @@ describe('webRequest module', () => { cancel: true }); }); - await expect(ajax(defaultURL)).to.eventually.be.rejectedWith('404'); + await expect(ajax(defaultURL)).to.eventually.be.rejected(); }); it('can filter URLs', async () => { @@ -82,7 +82,7 @@ describe('webRequest module', () => { }); const { data } = await ajax(`${defaultURL}nofilter/test`); expect(data).to.equal('/nofilter/test'); - await expect(ajax(`${defaultURL}filter/test`)).to.eventually.be.rejectedWith('404'); + await expect(ajax(`${defaultURL}filter/test`)).to.eventually.be.rejected(); }); it('receives details object', async () => { @@ -117,9 +117,9 @@ describe('webRequest module', () => { callback({ cancel: true }); }); await expect(ajax(defaultURL, { - type: 'POST', - data: postData - })).to.eventually.be.rejectedWith('404'); + method: 'POST', + body: qs.stringify(postData) + })).to.eventually.be.rejected(); }); it('can redirect the request', async () => { @@ -151,7 +151,7 @@ describe('webRequest module', () => { protocol: 'file', slashes: true }); - await expect(ajax(fileURL)).to.eventually.be.rejectedWith('404'); + await expect(ajax(fileURL)).to.eventually.be.rejected(); }); }); @@ -182,12 +182,12 @@ describe('webRequest module', () => { }); it('can change the request headers on a custom protocol redirect', async () => { - protocol.registerStringProtocol('custom-scheme', (req, callback) => { - if (req.url === 'custom-scheme://fake-host/redirect') { + protocol.registerStringProtocol('no-cors', (req, callback) => { + if (req.url === 'no-cors://fake-host/redirect') { callback({ statusCode: 302, headers: { - Location: 'custom-scheme://fake-host' + Location: 'no-cors://fake-host' } }); } else { @@ -202,7 +202,7 @@ describe('webRequest module', () => { // Note that we need to do navigation every time after a protocol is // registered or unregistered, otherwise the new protocol won't be // recognized by current page when NetworkService is used. - await contents.loadFile(path.join(__dirname, 'fixtures', 'pages', 'jquery.html')); + await contents.loadFile(path.join(__dirname, 'fixtures', 'pages', 'fetch.html')); try { ses.webRequest.onBeforeSendHeaders((details, callback) => { @@ -210,10 +210,10 @@ describe('webRequest module', () => { requestHeaders.Accept = '*/*;test/header'; callback({ requestHeaders: requestHeaders }); }); - const { data } = await ajax('custom-scheme://fake-host/redirect'); + const { data } = await ajax('no-cors://fake-host/redirect'); expect(data).to.equal('header-received'); } finally { - protocol.unregisterProtocol('custom-scheme'); + protocol.unregisterProtocol('no-cors'); } }); @@ -233,7 +233,7 @@ describe('webRequest module', () => { called = true; callback({ requestHeaders: details.requestHeaders }); }); - await ajax('neworigin://host'); + await ajax('cors://host'); expect(called).to.be.true(); }); @@ -320,7 +320,7 @@ describe('webRequest module', () => { callback({ responseHeaders: responseHeaders }); }); const { headers } = await ajax(defaultURL); - expect(headers).to.match(/^custom: Changed$/m); + expect(headers).to.to.have.property('custom', 'Changed'); }); it('can change response origin', async () => { @@ -330,7 +330,7 @@ describe('webRequest module', () => { callback({ responseHeaders: responseHeaders }); }); const { headers } = await ajax(defaultURL); - expect(headers).to.match(/^access-control-allow-origin: http:\/\/new-origin$/m); + expect(headers).to.to.have.property('access-control-allow-origin', 'http://new-origin'); }); it('can change headers of CORS responses', async () => { @@ -339,8 +339,8 @@ describe('webRequest module', () => { responseHeaders.Custom = ['Changed'] as any; callback({ responseHeaders: responseHeaders }); }); - const { headers } = await ajax('neworigin://host'); - expect(headers).to.match(/^custom: Changed$/m); + const { headers } = await ajax('cors://host'); + expect(headers).to.to.have.property('custom', 'Changed'); }); it('does not change header by default', async () => { @@ -348,7 +348,7 @@ describe('webRequest module', () => { callback({}); }); const { data, headers } = await ajax(defaultURL); - expect(headers).to.match(/^custom: Header$/m); + expect(headers).to.to.have.property('custom', 'Header'); expect(data).to.equal('/'); }); @@ -358,7 +358,7 @@ describe('webRequest module', () => { callback({}); }); const { data, headers } = await ajax(defaultURL + 'contentDisposition'); - expect(headers).to.match(/^content-disposition: attachment; filename=aa%E4%B8%ADaa.txt$/m); + expect(headers).to.to.have.property('content-disposition', 'attachment; filename=aa%E4%B8%ADaa.txt'); expect(data).to.equal('/contentDisposition'); }); @@ -368,7 +368,7 @@ describe('webRequest module', () => { callback({ responseHeaders: responseHeaders }); }); const { headers } = await ajax(defaultURL + 'serverRedirect'); - expect(headers).to.match(/^custom: Header$/m); + expect(headers).to.to.have.property('custom', 'Header'); }); it('can change the header status', async () => { @@ -379,19 +379,8 @@ describe('webRequest module', () => { statusLine: 'HTTP/1.1 404 Not Found' }); }); - const { headers } = await contents.executeJavaScript(`new Promise((resolve, reject) => { - const options = { - ...${JSON.stringify({ url: defaultURL })}, - success: (data, status, request) => { - reject(new Error('expected failure')) - }, - error: (xhr) => { - resolve({ headers: xhr.getAllResponseHeaders() }) - } - } - $.ajax(options) - })`); - expect(headers).to.match(/^custom: Header$/m); + const { headers } = await ajax(defaultURL); + expect(headers).to.to.have.property('custom', 'Header'); }); }); @@ -408,7 +397,7 @@ describe('webRequest module', () => { expect(details.responseHeaders!.Custom).to.deep.equal(['Header']); }); const { data, headers } = await ajax(defaultURL); - expect(headers).to.match(/^custom: Header$/m); + expect(headers).to.to.have.property('custom', 'Header'); expect(data).to.equal('/'); }); }); @@ -468,7 +457,7 @@ describe('webRequest module', () => { ses.webRequest.onErrorOccurred((details) => { expect(details.error).to.equal('net::ERR_BLOCKED_BY_CLIENT'); }); - await expect(ajax(defaultURL)).to.eventually.be.rejectedWith('404'); + await expect(ajax(defaultURL)).to.eventually.be.rejected(); }); }); diff --git a/spec-main/fixtures/pages/fetch.html b/spec-main/fixtures/pages/fetch.html new file mode 100644 index 0000000000..9e2ef64095 --- /dev/null +++ b/spec-main/fixtures/pages/fetch.html @@ -0,0 +1,15 @@ + +
+ + + diff --git a/spec-main/fixtures/pages/jquery-3.6.0.min.js b/spec-main/fixtures/pages/jquery-3.6.0.min.js new file mode 100644 index 0000000000..c4c6022f29 --- /dev/null +++ b/spec-main/fixtures/pages/jquery-3.6.0.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0