与Node.js相比,浏览器中的URL
对象(在本例中为Chrome)的行为不同。因此,我在Node中运行时会通过测试,但行为在浏览器中不匹配。
为了演示,这是一个简单的parseURL
函数,它试图从字符串中解析URL。如果它无法正确解析它,那么它会使用提供的字符串返回一个等同于Google搜索的网址。
function parseURL(query) {
const formattedQuery = query.includes('://') ? query : `http://${query}`;
try {
return new URL(formattedQuery);
} catch (err) {
return new URL(`https://www.google.com/search?q=${encodeURIComponent(query)}`);
}
}
还有一个简单的Jest测试来演示这个函数应该如何工作:
describe('parseURL', () => {
it('accepts valid URL string', () => {
expect(parseURL('https://example.com')).toEqual(
new URL('https://example.com')
);
});
it('prepends protocol when missing', () => {
expect(parseURL('example.com')).toEqual(
new URL('http://example.com')
);
});
it('converts search queries', () => {
expect(parseURL('example.com lol jk')).toEqual(
new URL('https://www.google.com/search?q=example.com+lol+jk')
);
});
});
前两个测试具有Node.js和浏览器的匹配行为。大!
但是,第三个测试在Node.js中传递,即使行为在浏览器内部不匹配。具体来说,在Node.js中调用new URL('http://example.com lol jk')
时,会引发错误。但是在浏览器中,不会引发错误,而是返回一个URL对象:
{
href: "http://example.com%20lol%20jk/",
origin: "http://example.com%20lol%20jk",
protocol: "http:",
username: "",
password: "",
hash: "",
host: "example.com%20lol%20jk",
hostname: "example.com%20lol%20jk",
href: "http://example.com%20lol%20jk/",
origin: "http://example.com%20lol%20jk",
password: "",
pathname: "/",
port: "",
protocol: "http:",
search: "",
searchParams: URLSearchParams {},
username: ""
}
在使用这样的对象时,我如何确信我的测试反映了浏览器中实际发生的情况?
问题是URL
在实现之间是不一致的。
这是预期的行为
new URL('http://example.com lol jk')
抛出错误,它不是有效的URL。它在Node.js和Firefox中正确实现,但在Chrome中没有(在这里被称为“浏览器”)。
依赖于Jest中的Node.js实现是安全的。如果生产中需要一致性,则需要使用符合规范的实现URL
替换whatwg-url
。