Skip to content

Commit

Permalink
Add tests for containing URL support (#1936)
Browse files Browse the repository at this point in the history
Closes #1903
  • Loading branch information
nex3 authored Sep 18, 2023
1 parent 3301bb5 commit 756ef27
Show file tree
Hide file tree
Showing 2 changed files with 279 additions and 2 deletions.
64 changes: 63 additions & 1 deletion js-api-spec/importer.node.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,13 @@
// https://opensource.org/licenses/MIT.

import {URL} from 'url';
import {compile, compileString, compileStringAsync, Importer} from 'sass';
import {
compile,
compileString,
compileStringAsync,
CanonicalizeContext,
Importer,
} from 'sass';

import {sandbox} from './sandbox';

Expand Down Expand Up @@ -278,6 +284,62 @@ describe('FileImporter', () => {
}));
});

describe('containingUrl is', () => {
it('set for a relative URL', () =>
sandbox(dir => {
dir.write({'_other.css': 'a {b: c}'});
const result = compileString('@import "other";', {
importers: [
{
findFileUrl: (url: string, context: CanonicalizeContext) => {
expect(context.containingUrl).toEqual(
new URL('x:original.scss')
);
return dir.url('other');
},
},
],
url: new URL('x:original.scss'),
});
expect(result.css).toBe('a {\n b: c;\n}');
}));

it('set for an absolute URL', () =>
sandbox(dir => {
dir.write({'_other.css': 'a {b: c}'});
const result = compileString('@import "u:other";', {
importers: [
{
findFileUrl: (url: string, context: CanonicalizeContext) => {
expect(context.containingUrl).toEqual(
new URL('x:original.scss')
);
return dir.url('other');
},
},
],
url: new URL('x:original.scss'),
});
expect(result.css).toBe('a {\n b: c;\n}');
}));

it('unset when the URL is unavailable', () =>
sandbox(dir => {
dir.write({'_other.css': 'a {b: c}'});
const result = compileString('@import "u:other";', {
importers: [
{
findFileUrl: (url: string, context: CanonicalizeContext) => {
expect(context.containingUrl).toBeNull();
return dir.url('other');
},
},
],
});
expect(result.css).toBe('a {\n b: c;\n}');
}));
});

describe('async', () => {
it('resolves an @import', async () =>
sandbox(async dir => {
Expand Down
217 changes: 216 additions & 1 deletion js-api-spec/importer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

import {compileString, compileStringAsync, Importer} from 'sass';
import {
compileString,
compileStringAsync,
CanonicalizeContext,
Importer,
} from 'sass';

import {sassImpl, URL} from './utils';

Expand Down Expand Up @@ -101,6 +106,216 @@ describe('the imported URL', () => {
});
});

describe('the containing URL', () => {
it('is null for a potentially canonical scheme', () => {
const result = compileString('@import "u:orange"', {
importers: [
{
canonicalize: (url: string, context: CanonicalizeContext) => {
expect(context.containingUrl).toBeNull();
return new URL(url);
},
load: () => ({contents: '@a', syntax: 'scss'}),
},
],
});

expect(result.css).toBe('@a;');
});

describe('for a non-canonical scheme', () => {
describe('in a list', () => {
it('is set to the original URL', () => {
const result = compileString('@import "u:orange"', {
importers: [
{
canonicalize: (url: string, context: CanonicalizeContext) => {
expect(context.containingUrl).toEqual(
new URL('x:original.scss')
);
return new URL(url.replace(/^u:/, 'x:'));
},
load: () => ({contents: '@a', syntax: 'scss'}),
nonCanonicalScheme: ['u'],
},
],
url: new URL('x:original.scss'),
});

expect(result.css).toBe('@a;');
});

it('is null if the original URL is null', () => {
const result = compileString('@import "u:orange"', {
importers: [
{
canonicalize: (url: string, context: CanonicalizeContext) => {
expect(context.containingUrl).toBeNull();
return new URL(url.replace(/^u:/, 'x:'));
},
load: () => ({contents: '@a', syntax: 'scss'}),
nonCanonicalScheme: ['u'],
},
],
});

expect(result.css).toBe('@a;');
});
});

describe('as a string', () => {
it('is set to the original URL', () => {
const result = compileString('@import "u:orange"', {
importers: [
{
canonicalize: (url: string, context: CanonicalizeContext) => {
expect(context.containingUrl).toEqual(
new URL('x:original.scss')
);
return new URL(url.replace(/^u:/, 'x:'));
},
load: () => ({contents: '@a', syntax: 'scss'}),
nonCanonicalScheme: 'u',
},
],
url: new URL('x:original.scss'),
});

expect(result.css).toBe('@a;');
});

it('is null if the original URL is null', () => {
const result = compileString('@import "u:orange"', {
importers: [
{
canonicalize: (url: string, context: CanonicalizeContext) => {
expect(context.containingUrl).toBeNull();
return new URL(url.replace(/^u:/, 'x:'));
},
load: () => ({contents: '@a', syntax: 'scss'}),
nonCanonicalScheme: 'u',
},
],
});

expect(result.css).toBe('@a;');
});
});
});

describe('for a schemeless load', () => {
it('is set to the original URL', () => {
const result = compileString('@import "orange"', {
importers: [
{
canonicalize: (url: string, context: CanonicalizeContext) => {
expect(context.containingUrl).toEqual(new URL('x:original.scss'));
return new URL(`u:${url}`);
},
load: () => ({contents: '@a', syntax: 'scss'}),
},
],
url: new URL('x:original.scss'),
});

expect(result.css).toBe('@a;');
});

it('is null if the original URL is null', () => {
const result = compileString('@import "orange"', {
importers: [
{
canonicalize: (url: string, context: CanonicalizeContext) => {
expect(context.containingUrl).toBeNull();
return new URL(`u:${url}`);
},
load: () => ({contents: '@a', syntax: 'scss'}),
},
],
});

expect(result.css).toBe('@a;');
});
});
});

describe(
'throws an error if the importer returns a canonical URL with a ' +
'non-canonical scheme',
() => {
it('set as a list', () =>
expect(() =>
compileString('@import "orange"', {
importers: [
{
canonicalize: (url: string) => {
return new URL(`u:${url}`);
},
load: () => ({contents: '@a', syntax: 'scss'}),
nonCanonicalScheme: ['u'],
},
],
})
).toThrowSassException({line: 0}));

it('set as a string', () =>
expect(() =>
compileString('@import "orange"', {
importers: [
{
canonicalize: (url: string) => {
return new URL(`u:${url}`);
},
load: () => ({contents: '@a', syntax: 'scss'}),
nonCanonicalScheme: 'u',
},
],
})
).toThrowSassException({line: 0}));
}
);

describe('throws an error for an invalid scheme:', () => {
it('empty', () =>
expect(() =>
compileString('a {b: c}', {
importers: [
{
canonicalize: () => null,
load: () => ({contents: '@a', syntax: 'scss'}),
nonCanonicalScheme: '',
},
],
})
).toThrow());

it('uppercase', () =>
expect(() =>
compileString('a {b: c}', {
importers: [
{
canonicalize: () => null,
load: () => ({contents: '@a', syntax: 'scss'}),
nonCanonicalScheme: 'U',
},
],
})
).toThrow());

it('colon', () =>
expect(() =>
compileString('a {b: c}', {
importers: [
{
canonicalize: () => null,
load: () => ({contents: '@a', syntax: 'scss'}),
nonCanonicalScheme: 'u:',
},
],
})
).toThrow());
});

it("uses an importer's source map URL", () => {
const result = compileString('@import "orange";', {
importers: [
Expand Down

0 comments on commit 756ef27

Please sign in to comment.