/
githubmirror
/
amphtml
Обзор
Документация
Войти
/
githubmirror
/
amphtml
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
test/unit/test-url.js
1 079 строк
31 KB
Daniel Rozenberg
✅ Fix tests broken by changes from https://twitter.com/ to https://x.com/ (#40016)
20 май 2024, 20:12
Не верифицирован
20 май 2024, 20:12
d15fbae
Код
Авторство
О чём код?
import {Services} from '#service'; import { addMissingParamsToUrl, addParamToUrl, addParamsToUrl, appendPathToUrl, assertAbsoluteHttpOrHttpsUrl, assertHttpsUrl, getCorsUrl, getProxyServingType, getSourceOrigin, getSourceUrl, getWinOrigin, isLocalhostOrigin, isProtocolValid, isProxyOrigin, isSecureUrlDeprecated, parseUrlDeprecated, removeAmpJsParamsFromUrl, removeFragment, removeParamsFromSearch, removeSearch, resolveRelativeUrl, resolveRelativeUrlFallback_, serializeQueryString, } from '../../src/url'; describes.sandboxed('getWinOrigin', {}, () => { it('should return origin if available', () => { expect( getWinOrigin({ 'origin': 'https://foo.com', 'location': { 'href': 'https://foo1.com/abc?123#foo', }, }) ).to.equal('https://foo.com'); }); it('should return origin from href when win.origin is not available', () => { expect( getWinOrigin({ 'location': { 'href': 'https://foo1.com/abc?123#foo', }, }) ).to.equal('https://foo1.com'); }); it('should return origin from href when win.origin is empty', () => { expect( getWinOrigin({ 'origin': '', 'location': { 'href': 'https://foo1.com/abc?123#foo', }, }) ).to.equal('https://foo1.com'); }); it('should return origin from href when win.origin is null', () => { expect( getWinOrigin({ 'origin': null, 'location': { 'href': 'https://foo1.com/abc?123#foo', }, }) ).to.equal('https://foo1.com'); }); it('should return "null" when win.origin is "null"', () => { expect( getWinOrigin({ 'origin': 'null', 'location': { 'href': 'https://foo1.com/abc?123#foo', }, }) ).to.equal('null'); }); }); describes.sandboxed('parseUrlDeprecated', {}, () => { const currentPort = location.port; function compareParse(url, result) { // Using JSON string comparison because Chai's deeply equal // errors are impossible to debug. const parsed = JSON.stringify(parseUrlDeprecated(url)); const expected = JSON.stringify(result); expect(parsed).to.equal(expected); } it('should parse correctly', () => { compareParse('https://foo.com/abc?123#foo', { href: 'https://foo.com/abc?123#foo', protocol: 'https:', host: 'foo.com', hostname: 'foo.com', port: '', pathname: '/abc', search: '?123', hash: '#foo', origin: 'https://foo.com', }); }); it('caches results', () => { const url = 'https://foo.com:123/abc?123#foo'; parseUrlDeprecated(url); const a1 = parseUrlDeprecated(url); const a2 = parseUrlDeprecated(url); expect(a1).to.equal(a2); }); it('caches up to 100 results', () => { const url = 'https://foo.com:123/abc?123#foo'; const a1 = parseUrlDeprecated(url); // should grab url from the cache expect(a1).to.equal(parseUrlDeprecated(url)); // cache 99 more urls in order to reach max capacity of LRU cache: 100 for (let i = 0; i < 100; i++) { parseUrlDeprecated(`${url}-${i}`); } const a2 = parseUrlDeprecated(url); // the old cached url should not be in the cache anymore // the newer instance should expect(a1).to.not.equal(parseUrlDeprecated(url)); expect(a2).to.equal(parseUrlDeprecated(url)); expect(a1).to.not.equal(a2); }); it('should handle ports', () => { compareParse('https://foo.com:123/abc?123#foo', { href: 'https://foo.com:123/abc?123#foo', protocol: 'https:', host: 'foo.com:123', hostname: 'foo.com', port: '123', pathname: '/abc', search: '?123', hash: '#foo', origin: 'https://foo.com:123', }); }); it('should omit HTTP default port', () => { compareParse('http://foo.com:80/abc?123#foo', { href: 'http://foo.com/abc?123#foo', protocol: 'http:', host: 'foo.com', hostname: 'foo.com', port: '', pathname: '/abc', search: '?123', hash: '#foo', origin: 'http://foo.com', }); }); it('should omit HTTPS default port', () => { compareParse('https://foo.com:443/abc?123#foo', { href: 'https://foo.com/abc?123#foo', protocol: 'https:', host: 'foo.com', hostname: 'foo.com', port: '', pathname: '/abc', search: '?123', hash: '#foo', origin: 'https://foo.com', }); }); it('should support http', () => { compareParse('http://foo.com:123/abc?123#foo', { href: 'http://foo.com:123/abc?123#foo', protocol: 'http:', host: 'foo.com:123', hostname: 'foo.com', port: '123', pathname: '/abc', search: '?123', hash: '#foo', origin: 'http://foo.com:123', }); }); it('should resolve relative urls', () => { compareParse('./abc?123#foo', { href: 'http://localhost:' + currentPort + '/abc?123#foo', protocol: 'http:', host: 'localhost:' + currentPort, hostname: 'localhost', port: currentPort, pathname: '/abc', search: '?123', hash: '#foo', origin: 'http://localhost:' + currentPort, }); }); it('should resolve path relative urls', () => { compareParse('/abc?123#foo', { href: 'http://localhost:' + currentPort + '/abc?123#foo', protocol: 'http:', host: 'localhost:' + currentPort, hostname: 'localhost', port: currentPort, pathname: '/abc', search: '?123', hash: '#foo', origin: 'http://localhost:' + currentPort, }); }); it('should handle URLs with just the domain', () => { compareParse('http://foo.com:123', { href: 'http://foo.com:123/', protocol: 'http:', host: 'foo.com:123', hostname: 'foo.com', port: '123', pathname: '/', search: '', hash: '', origin: 'http://foo.com:123', }); }); it('should parse origin https://x.com/path#abc', () => { expect(parseUrlDeprecated('https://x.com/path#abc').origin).to.equal( 'https://x.com' ); }); it('should parse origin data:12345', () => { expect(parseUrlDeprecated('data:12345').origin).to.equal('data:12345'); }); it('should parse relative', () => { expect(parseUrlDeprecated('chilaquiles/rojos')).to.include({ pathname: '/chilaquiles/rojos', }); }); }); describes.sandboxed('serializeQueryString', {}, () => { it('should return empty string for empty params', () => { expect(serializeQueryString({})).to.equal(''); expect( serializeQueryString({ nullValue: null, undefValue: undefined, }) ).to.equal(''); }); it('should serialize a single value', () => { expect(serializeQueryString({a: 'A'})).to.equal('a=A'); }); it('should serialize multiple values', () => { expect(serializeQueryString({a: 'A', b: 'B'})).to.equal('a=A&b=B'); }); it('should coerce to string', () => { expect(serializeQueryString({a: 1, b: true})).to.equal('a=1&b=true'); }); it('should encode values and keys', () => { expect(serializeQueryString({'a+b': 'A+B'})).to.equal('a%2Bb=A%2BB'); }); it('should serialize multiple valued parameters', () => { expect(serializeQueryString({a: [1, 2, 3], b: true})).to.equal( 'a=1&a=2&a=3&b=true' ); }); }); describes.sandboxed('assertHttpsUrl/isSecureUrl', {}, () => { const referenceElement = document.createElement('div'); it('should NOT allow null or undefined, but allow empty string', () => { allowConsoleError(() => { expect(() => { assertHttpsUrl(null, referenceElement); }).to.throw(/source must be available/); expect(() => { assertHttpsUrl(undefined, referenceElement); }).to.throw(/source must be available/); }); assertHttpsUrl('', referenceElement); }); it('should allow https', () => { assertHttpsUrl('https://x.com', referenceElement); expect(isSecureUrlDeprecated('https://x.com')).to.be.true; }); it('should allow protocol relative', () => { assertHttpsUrl('//x.com', referenceElement); // `isSecureUrl` always resolves relative URLs. expect(isSecureUrlDeprecated('//x.com')).to.be.equal( window.location.protocol == 'https:' ); }); it('should allow localhost with http', () => { assertHttpsUrl('http://localhost:8000/sfasd', referenceElement); expect(isSecureUrlDeprecated('http://localhost:8000/sfasd')).to.be.true; }); it('should allow localhost with http suffix', () => { assertHttpsUrl('http://iframe.localhost:8000/sfasd', referenceElement); expect(isSecureUrlDeprecated('http://iframe.localhost:8000/sfasd')).to.be .true; }); it('should fail on http', () => { allowConsoleError(() => { expect(() => { assertHttpsUrl('http://x.com', referenceElement); }).to.throw(/source must start with/); }); expect(isSecureUrlDeprecated('http://x.com')).to.be.false; }); it('should fail on http with localhost in the name', () => { allowConsoleError(() => { expect(() => { assertHttpsUrl('http://foolocalhost', referenceElement); }).to.throw(/source must start with/); }); expect(isSecureUrlDeprecated('http://foolocalhost')).to.be.false; }); }); describes.sandboxed('assertAbsoluteHttpOrHttpsUrl', {}, () => { it('should allow http', () => { expect(assertAbsoluteHttpOrHttpsUrl('http://x.com/')).to.equal( 'http://x.com/' ); expect(assertAbsoluteHttpOrHttpsUrl('HTTP://x.com/')).to.equal( 'http://x.com/' ); }); it('should allow https', () => { expect(assertAbsoluteHttpOrHttpsUrl('https://x.com/')).to.equal( 'https://x.com/' ); expect(assertAbsoluteHttpOrHttpsUrl('HTTPS://x.com/')).to.equal( 'https://x.com/' ); }); it('should fail on relative protocol', () => { allowConsoleError(() => { expect(() => { assertAbsoluteHttpOrHttpsUrl('//x.com/'); }).to.throw(/URL must start with/); }); }); it('should fail on relative url', () => { allowConsoleError(() => { expect(() => { assertAbsoluteHttpOrHttpsUrl('/path'); }).to.throw(/URL must start with/); }); }); it('should fail on not allowed protocol', () => { allowConsoleError(() => { expect(() => { assertAbsoluteHttpOrHttpsUrl( /*eslint no-script-url: 0*/ 'javascript:alert' ); }).to.throw(/URL must start with/); }); }); }); describes.sandboxed('removeFragment', {}, () => { it('should remove fragment', () => { expect(removeFragment('https://x.com/path#abc')).to.equal( 'https://x.com/path' ); }); it('should remove empty fragment', () => { expect(removeFragment('https://x.com/path#')).to.equal( 'https://x.com/path' ); }); it('should ignore when no fragment', () => { expect(removeFragment('https://x.com/path')).to.equal('https://x.com/path'); }); }); describes.sandboxed('removeSearch', {}, () => { it('should remove search', () => { expect(removeSearch('https://x.com/path?abc')).to.equal( 'https://x.com/path' ); }); it('should remove search with value', () => { expect(removeSearch('https://x.com/path?abc=123')).to.equal( 'https://x.com/path' ); }); it('should remove multiple params', () => { expect(removeSearch('https://x.com/path?abc=123&d&e=4')).to.equal( 'https://x.com/path' ); }); it('should remove empty search', () => { expect(removeSearch('https://x.com/path?')).to.equal('https://x.com/path'); }); it('should ignore when no search', () => { expect(removeSearch('https://x.com/path')).to.equal('https://x.com/path'); }); it('should preserve fragment', () => { expect(removeSearch('https://x.com/path?abc#f')).to.equal( 'https://x.com/path#f' ); }); it('should preserve fragment with multiple params', () => { expect(removeSearch('https://x.com/path?a&d=1&e=5#f=x')).to.equal( 'https://x.com/path#f=x' ); }); it('should preserve fragment when no search', () => { expect(removeSearch('https://x.com/path#f')).to.equal( 'https://x.com/path#f' ); }); it('should handle empty fragment', () => { expect(removeSearch('https://x.com/path#')).to.equal('https://x.com/path#'); expect(removeSearch('https://x.com/path?#')).to.equal( 'https://x.com/path#' ); }); }); describes.sandboxed('addParamToUrl', {}, () => { let url; beforeEach(() => { url = 'https://www.ampproject.org/get/here#hash-value'; }); it('should preserve hash value', () => { url = addParamToUrl(url, 'elementId', 'n1'); expect(url).to.equal( 'https://www.ampproject.org/get/here?elementId=n1#hash-value' ); url = addParamToUrl(url, 'ampUserId', '12345'); expect(url).to.equal( 'https://www.ampproject.org/get/here?elementId=n1&UserId=12345#hash-value' ); }); it('should preserve query values', () => { url = 'https://www.ampproject.org/get/here?hello=world&foo=bar'; url = addParamToUrl(url, 'elementId', 'n1'); expect(url).to.equal( 'https://www.ampproject.org/get/here?hello=world&foo=bar&elementId=n1' ); url = addParamToUrl(url, 'ampUserId', '12345'); expect(url).to.equal( 'https://www.ampproject.org/get/here?hello=world&foo=bar&elementId=n1&UserId=12345' ); }); it('should optionally add params to the front', () => { let url = addParamToUrl( 'https://www.ampproject.org/get/here?hello=world&foo=bar', 'elementId', 'n1', /* addToFront */ true ); expect(url).to.equal( 'https://www.ampproject.org/get/here?elementId=n1&hello=world&foo=bar' ); url = addParamToUrl( 'https://www.ampproject.org/get/here', 'elementId', 'n1', /* addToFront */ true ); expect(url).to.equal('https://www.ampproject.org/get/here?elementId=n1'); }); it('should encode uri values', () => { url = addParamToUrl(url, 'foo', 'b ar'); expect(url).to.equal( 'https://www.ampproject.org/get/here?foo=b%20ar#hash-value' ); }); it('should keep host and path intact', () => { url = addParamToUrl('https://${host}/${path}', 'foo', 'bar'); expect(url).to.equal('https://${host}/${path}?foo=bar'); }); }); describes.sandboxed('addParamsToUrl', {}, () => { let url; const params = { hello: 'world', foo: 'bar', }; beforeEach(() => { url = 'https://www.ampproject.org/get/here#hash-value'; }); it('should loop over the keys and values correctly', () => { url = addParamsToUrl(url, params); expect(url).to.equal( 'https://www.ampproject.org/get/here?hello=world&foo=bar#hash-value' ); expect( addParamsToUrl('http://example.com', { firstname: 'Cool', lastname: 'Beans', interests: ['Basketball', 'Food', 'Running'], }) ).to.equal( 'http://example.com?firstname=Cool&lastname=Beans&' + 'interests=Basketball&interests=Food&interests=Running' ); }); it('should keep host and path intact', () => { url = addParamsToUrl('https://${host}/${path}#hash-value', params); expect(url).to.equal( 'https://${host}/${path}?hello=world&foo=bar#hash-value' ); }); }); describes.sandboxed('addMissingParamsToUrl', {}, () => { let url; const params = { hello: 'world', foo: 'bar', replace: 'error', safe: 'error', }; beforeEach(() => { url = 'https://www.ampproject.org/get/here?replace=1&safe#hash-value'; }); it('should not replace existing params', () => { expect(addMissingParamsToUrl(url, params)).to.equal( 'https://www.ampproject.org/get/here?replace=1&safe&hello=world&foo=bar#hash-value' ); }); }); describes.sandboxed('isProxyOrigin', {}, () => { function testProxyOrigin(href, bool) { it( 'should return that ' + href + (bool ? ' is' : ' is not') + ' a proxy origin', () => { expect(isProxyOrigin(parseUrlDeprecated(href))).to.equal(bool); } ); } // CDN testProxyOrigin('https://cdn.ampproject.org/', true); testProxyOrigin('http://cdn.ampproject.org/', false); testProxyOrigin('https://cdn.ampproject.org.badguys.com/', false); testProxyOrigin('https://cdn.ampproject.orgbadguys.com/', false); testProxyOrigin('https://cdn.ampproject.org:1234', false); testProxyOrigin('https://cdn.ampproject.org/v/www.origin.com/foo/?f=0', true); testProxyOrigin('https://cdn.ampproject.org/c/www.origin.com/foo/?f=0', true); // Prefixed CDN testProxyOrigin('https://xyz.cdn.ampproject.org/', true); testProxyOrigin('http://xyz.cdn.ampproject.org/', false); testProxyOrigin('https://xyz-123.cdn.ampproject.org/', true); testProxyOrigin( 'https://xyz.cdn.ampproject.org/v/www.origin.com/foo/?f=0', true ); testProxyOrigin( 'https://xyz.cdn.ampproject.org/c/www.origin.com/foo/?f=0', true ); // Others testProxyOrigin('http://localhost:123', false); testProxyOrigin( 'https://cdn.ampproject.net/v/www.origin.com/foo/?f=0', false ); testProxyOrigin( 'https://medium.com/swlh/nobody-wants-your-app-6af1f7f69cb7', false ); testProxyOrigin( 'http://www.spiegel.de/politik/deutschland/angela-merkel-a-1062761.html', false ); }); describes.sandboxed('isLocalhostOrigin', {}, () => { function testLocalhostOrigin(href, bool) { it( 'should return that ' + href + (bool ? ' is' : ' is not') + ' a localhost origin', () => { expect(isLocalhostOrigin(parseUrlDeprecated(href))).to.equal(bool); } ); } testLocalhostOrigin('http://localhost', true); testLocalhostOrigin('https://localhost', true); testLocalhostOrigin('http://localhost:123/foo.html', true); testLocalhostOrigin('https://localhost:123/foo.html', true); testLocalhostOrigin('http://localhost.example.com/foo.html', false); testLocalhostOrigin('http://www.example.com/foo.html', false); }); describes.sandboxed('isProtocolValid', {}, () => { function testProtocolValid(href, bool) { it( 'should return that ' + href + (bool ? ' is' : ' is not') + ' a valid protocol', () => { expect(isProtocolValid(href)).to.equal(bool); } ); } testProtocolValid('http://foo.com', true); testProtocolValid('https://foo.com', true); testProtocolValid('bar://foo.com', true); testProtocolValid('', true); testProtocolValid('foo', true); testProtocolValid('./foo', true); testProtocolValid('/foo', true); testProtocolValid('//foo.com', true); testProtocolValid(undefined, true); testProtocolValid(null, true); testProtocolValid('javascript:alert("hello world!");', false); testProtocolValid('data:12345', false); testProtocolValid('vbscript:foo', false); }); describes.sandboxed('getSourceOrigin/Url', {}, () => { function testOrigin(href, sourceHref) { it('should return the source origin/url from ' + href, () => { expect(getSourceUrl(href)).to.equal(sourceHref); expect(getSourceOrigin(href)).to.equal( parseUrlDeprecated(sourceHref).origin ); }); } // CDN. testOrigin( 'https://cdn.ampproject.org/v/www.origin.com/foo/?f=0#h', 'http://www.origin.com/foo/?f=0#h' ); testOrigin( 'https://cdn.ampproject.org/v/s/www.origin.com/foo/?f=0#h', 'https://www.origin.com/foo/?f=0#h' ); testOrigin( 'https://cdn.ampproject.org/c/www.origin.com/foo/?f=0', 'http://www.origin.com/foo/?f=0' ); testOrigin( 'https://cdn.ampproject.org/c/s/www.origin.com/foo/?f=0', 'https://www.origin.com/foo/?f=0' ); testOrigin( 'https://cdn.ampproject.org/c/s/origin.com/foo/?f=0', 'https://origin.com/foo/?f=0' ); testOrigin( 'https://cdn.ampproject.org/c/s/origin.com%3A81/foo/?f=0', 'https://origin.com:81/foo/?f=0' ); testOrigin( 'https://cdn.ampproject.org/a/www.origin.com/foo/?f=0#h', 'http://www.origin.com/foo/?f=0#h' ); testOrigin( 'https://cdn.ampproject.org/ad/www.origin.com/foo/?f=0#h', 'http://www.origin.com/foo/?f=0#h' ); // Prefixed CDN testOrigin( 'https://xyz.cdn.ampproject.org/v/www.origin.com/foo/?f=0#h', 'http://www.origin.com/foo/?f=0#h' ); testOrigin( 'https://xyz.cdn.ampproject.org/v/s/www.origin.com/foo/?f=0#h', 'https://www.origin.com/foo/?f=0#h' ); testOrigin( 'https://xyz.cdn.ampproject.org/c/www.origin.com/foo/?f=0', 'http://www.origin.com/foo/?f=0' ); testOrigin( 'https://xyz.cdn.ampproject.org/c/s/www.origin.com/foo/?f=0', 'https://www.origin.com/foo/?f=0' ); testOrigin( 'https://xyz.cdn.ampproject.org/c/s/origin.com/foo/?f=0', 'https://origin.com/foo/?f=0' ); testOrigin( 'https://xyz.cdn.ampproject.org/c/s/origin.com%3A81/foo/?f=0', 'https://origin.com:81/foo/?f=0' ); // Removes amp-related paramters. testOrigin( 'https://cdn.ampproject.org/c/o.com/foo/?amp_js_param=5', 'http://o.com/foo/' ); testOrigin( 'https://cdn.ampproject.org/c/o.com/foo/?f=0&_js_v=5#something', 'http://o.com/foo/?f=0#something' ); testOrigin( 'https://cdn.ampproject.org/c/o.com/foo/?amp_js_v=5&f=0#bar', 'http://o.com/foo/?f=0#bar' ); testOrigin( 'https://cdn.ampproject.org/c/o.com/foo/?f=0&_js_param=5&d=5#baz', 'http://o.com/foo/?f=0&d=5#baz' ); testOrigin( 'https://cdn.ampproject.org/c/o.com/foo/?f_amp_js_param=5&d=5', 'http://o.com/foo/?f_amp_js_param=5&d=5' ); testOrigin( 'https://cdn.ampproject.org/c/o.com/foo/?amp_js_param=5?d=5', 'http://o.com/foo/' ); // Treats amp_js_param=5?d=5 as one param. testOrigin( 'https://cdn.ampproject.org/c/o.com/foo/&_js_param=5&d=5', 'http://o.com/foo/&_js_param=5&d=5' ); // Treats &... as part of path. testOrigin( 'https://cdn.ampproject.org/c/o.com/foo/?amp_r=test%3Dhello%20world', 'http://o.com/foo/' ); // Removes google experimental queryString parameters. testOrigin( 'https://cdn.ampproject.org/c/o.com/foo/?usqp=mq331AQCCAE', 'http://o.com/foo/' ); testOrigin( 'https://cdn.ampproject.org/c/o.com/foo/?usqp=mq331AQCCAE&_js_param=5', 'http://o.com/foo/' ); testOrigin( 'https://cdn.ampproject.org/c/o.com/foo/?amp_js_param=5&usqp=mq331AQCCAE', 'http://o.com/foo/' ); testOrigin( 'https://cdn.ampproject.org/c/o.com/foo/?usqp=mq331AQCCAE&bar=1&_js_param=5', 'http://o.com/foo/?bar=1' ); testOrigin( 'https://cdn.ampproject.org/c/o.com/foo/?f=0&usqp=mq331AQCCAE#something', 'http://o.com/foo/?f=0#something' ); testOrigin( 'https://cdn.ampproject.org/c/o.com/foo/?usqp=mq331AQCCAE&f=0#bar', 'http://o.com/foo/?f=0#bar' ); testOrigin( 'https://cdn.ampproject.org/c/o.com/foo/?f=0&usqp=mq331AQCCAE&d=5#baz', 'http://o.com/foo/?f=0&d=5#baz' ); testOrigin( 'https://cdn.ampproject.org/c/o.com/foo/?f_usqp=mq331AQCCAE&d=5', 'http://o.com/foo/?f_usqp=mq331AQCCAE&d=5' ); testOrigin( 'https://cdn.ampproject.org/c/o.com/foo/?usqp=mq331AQCCAE?d=5', 'http://o.com/foo/' ); // Treats amp_js_param=5?d=5 as one param. testOrigin( 'https://cdn.ampproject.org/c/o.com/foo/&usqp=mq331AQCCAE&d=5', 'http://o.com/foo/&usqp=mq331AQCCAE&d=5' ); // Treats &... as part of path. // Non-CDN. testOrigin('https://origin.com/foo/?f=0', 'https://origin.com/foo/?f=0'); it('should fail on invalid source origin', () => { allowConsoleError(() => { expect(() => { getSourceOrigin( parseUrlDeprecated('https://cdn.ampproject.org/v/yyy/') ); }).to.throw(/Expected a \. in origin http:\/\/yyy/); }); }); }); describes.sandboxed('resolveRelativeUrl', {}, () => { function testRelUrl(href, baseHref, resolvedHref) { it( 'should return the resolved rel url from ' + href + ' with base ' + baseHref, () => { expect(resolveRelativeUrl(href, baseHref)).to.equal( resolvedHref, 'native or fallback' ); expect(resolveRelativeUrlFallback_(href, baseHref)).to.equal( resolvedHref, 'fallback' ); } ); } // Absolute URL. testRelUrl( 'https://acme.org/path/file?f=0#h', 'https://base.org/bpath/bfile?bf=0#bh', 'https://acme.org/path/file?f=0#h' ); testRelUrl( 'data:12345', 'https://base.org/bpath/bfile?bf=0#bh', 'data:12345' ); // Protocol-relative URL. testRelUrl( '//acme.org/path/file?f=0#h', 'https://base.org/bpath/bfile?bf=0#bh', 'https://acme.org/path/file?f=0#h' ); testRelUrl( '//acme.org/path/file?f=0#h', 'http://base.org/bpath/bfile?bf=0#bh', 'http://acme.org/path/file?f=0#h' ); // Absolute path. testRelUrl( '/path/file?f=0#h', 'https://base.org/bpath/bfile?bf=0#bh', 'https://base.org/path/file?f=0#h' ); testRelUrl( '/path/file?f=0#h', 'http://base.org/bpath/bfile?bf=0#bh', 'http://base.org/path/file?f=0#h' ); testRelUrl( '\\path/file?f=0#h', 'http://base.org/bpath/bfile?bf=0#bh', 'http://base.org/path/file?f=0#h' ); // Relative path. testRelUrl( 'file?f=0#h', 'https://base.org/bpath/bfile?bf=0#bh', 'https://base.org/bpath/file?f=0#h' ); testRelUrl( 'file?f=0#h', 'http://base.org/bpath/bfile?bf=0#bh', 'http://base.org/bpath/file?f=0#h' ); testRelUrl( 'file?f=0#h', 'https://base.org/bfile?bf=0#bh', 'https://base.org/file?f=0#h' ); testRelUrl( 'file?f=0#h', 'http://base.org/bfile?bf=0#bh', 'http://base.org/file?f=0#h' ); // Accepts parsed URLs. testRelUrl( 'file?f=0#h', parseUrlDeprecated('http://base.org/bfile?bf=0#bh'), 'http://base.org/file?f=0#h' ); }); describes.sandboxed('getCorsUrl', {}, () => { it('should error if __amp_source_origin is set', () => { allowConsoleError(() => { expect(() => getCorsUrl(window, 'http://example.com/?__amp_source_origin') ).to.throw(/Source origin is not allowed in/); }); expect(() => getCorsUrl(window, 'http://example.com/?name=hello') ).to.not.throw(); }); it('should set __amp_source_origin as a url param', () => { expect(getCorsUrl(window, 'http://example.com/?name=hello')).to.equal( 'http://example.com/?name=hello&' + '__amp_source_origin=http%3A%2F%2Flocalhost%3A9876' ); }); }); describes.sandboxed('removeAmpJsParamsFromUrl', {}, () => { it('should handle unaffected URLs', () => { expect(removeAmpJsParamsFromUrl('http://example.com')).to.equal( 'http://example.com/' ); expect(removeAmpJsParamsFromUrl('http://example.com?x=123')).to.equal( 'http://example.com/?x=123' ); expect(removeAmpJsParamsFromUrl('http://example.com#x=123')).to.equal( 'http://example.com/#x=123' ); expect(removeAmpJsParamsFromUrl('http://example.com?y=abc#x=123')).to.equal( 'http://example.com/?y=abc#x=123' ); }); it('should remove all internal params', () => { expect( removeAmpJsParamsFromUrl( 'http://example.com?amp_js=1&_gsa=2&_r=3&_kit=4&usqp=4' ) ).to.equal('http://example.com/'); expect( removeAmpJsParamsFromUrl( 'http://example.com?amp_js&_gsa&_r&_kit&usqp' ) ).to.equal('http://example.com/'); }); it('should remove all internal params, leaving others intact', () => { expect( removeAmpJsParamsFromUrl( 'http://example.com?a=a&_js=1&b=b&_gsa=2&c=c&_r=3&_kit=4&d=d&usqp=4&e=e' ) ).to.equal('http://example.com/?a=a&b=b&c=c&d=d&e=e'); }); it('should preserve the fragment', () => { expect( removeAmpJsParamsFromUrl( 'http://example.com?a=a&_js=1&b=b&_gsa=2&c=c&_r=3&_kit=4&d=d&usqp=4&e=e#frag=yes' ) ).to.equal('http://example.com/?a=a&b=b&c=c&d=d&e=e#frag=yes'); }); it('should preserve the path', () => { expect( removeAmpJsParamsFromUrl( 'http://example.com/toast?a=a&_js=1&b=b&_gsa=2&c=c&_r=3&_kit=4&d=d&usqp=4&e=e#frag=yes' ) ).to.equal('http://example.com/toast?a=a&b=b&c=c&d=d&e=e#frag=yes'); }); }); describes.sandboxed('removeParamsFromSearch', {}, () => { it('should remove the leading ? or &', () => { expect(removeParamsFromSearch('?a=1&', 'a')).to.equal(''); }); it('should remove the param from searchUrl', () => { expect(removeParamsFromSearch('?a=1&b=2&c', 'a')).to.equal('?b=2&c'); }); it('should remove all param with same name from searchUrl', () => { expect(removeParamsFromSearch('?a=1&b=2&a=2&a=3&c&ab=3', 'a')).to.equal( '?b=2&c&ab=3' ); }); }); describes.sandboxed('getProxyServingType', {}, () => { it('should ignore non-proxy origins', () => { expect(getProxyServingType('http://www.example.com')).to.be.null; expect(getProxyServingType('http://cdn.ampproject.org/c/o.com/foo/')).to.be .null; }); it('should correctly extract known types', () => { expect( getProxyServingType('https://cdn.ampproject.org/c/o.com/foo/') ).to.equal('c'); expect( getProxyServingType('https://cdn.ampproject.org/a/o.com/foo/') ).to.equal('a'); expect( getProxyServingType('https://cdn.ampproject.org/v/o.com/foo/') ).to.equal('v'); }); it('should correctly extract unknown types', () => { expect( getProxyServingType('https://cdn.ampproject.org/test/o.com/foo/') ).to.equal('test'); expect( getProxyServingType('https://not.cdn.ampproject.org/test/o.com/foo/') ).to.equal('test'); expect( getProxyServingType('https://not.cdn.ampproject.org/test/blah.com/foo/') ).to.equal('test'); }); }); describes.realWin('appendPathToUrl', {'amp': true}, (env) => { let urlService; beforeEach(() => { urlService = Services.urlForDoc(env.win.document.body); }); it('should properly join url and path', () => { expect( appendPathToUrl(urlService.parse('https://cdn.ampproject.org'), '/foo') ).to.be.equal('https://cdn.ampproject.org/foo'); }); it('should join url and path if none contain /', () => { expect( appendPathToUrl(urlService.parse('https://cdn.ampproject.org'), 'foo') ).to.be.equal('https://cdn.ampproject.org/foo'); }); it('should properly join url with path, and path', () => { expect( appendPathToUrl( urlService.parse('https://cdn.ampproject.org/bar/'), '/foo' ) ).to.be.equal('https://cdn.ampproject.org/bar/foo'); }); it('should add path before query params', () => { expect( appendPathToUrl( urlService.parse('https://cdn.ampproject.org?a=b'), '/foo' ) ).to.be.equal('https://cdn.ampproject.org/foo?a=b'); }); it('should add path before fragment', () => { expect( appendPathToUrl( urlService.parse('https://cdn.ampproject.org/#hello'), '/foo' ) ).to.be.equal('https://cdn.ampproject.org/foo#hello'); }); it('should add path before query params and fragment', () => { expect( appendPathToUrl( urlService.parse('https://cdn.ampproject.org?a=b#hello'), 'foo' ) ).to.be.equal('https://cdn.ampproject.org/foo?a=b#hello'); }); });