Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions test/font.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
describe('Fonts', function () {
describe('/fonts.json', function () {
it('returns 200 with application/json', function (done) {
supertest(app)
.get('/fonts.json')
.expect(200)
.expect('Content-Type', /application\/json/, done);
});

it('returns non-empty array of font names', function (done) {
supertest(app)
.get('/fonts.json')
.expect(function (res) {
expect(res.body).to.be.a('array');
expect(res.body.length).to.be.greaterThan(0);
})
.end(done);
});

it('returns sorted font names', function (done) {
supertest(app)
.get('/fonts.json')
.expect(function (res) {
const sorted = [...res.body].sort();
expect(res.body).to.deep.equal(sorted);
})
.end(done);
});
});

describe('/fonts/:fontstack/:range.pbf', function () {
describe('valid single font', function () {
it('returns 200 with application/x-protobuf', function (done) {
supertest(app)
.get('/fonts/Open%20Sans%20Bold/0-255.pbf')
.expect(200)
.expect('Content-Type', /application\/x-protobuf/, done);
});

it('returns non-empty body', function (done) {
supertest(app)
.get('/fonts/Open%20Sans%20Bold/0-255.pbf')
.expect(function (res) {
const length = parseInt(res.headers['content-length'], 10);
expect(length).to.be.greaterThan(0);
})
.end(done);
});

it('sets Last-Modified header', function (done) {
supertest(app)
.get('/fonts/Open%20Sans%20Regular/0-255.pbf')
.expect(200)
.expect(function (res) {
expect(res.headers['last-modified']).to.be.a('string');
})
.end(done);
});
});

describe('valid combined font stack', function () {
it('returns 200 for comma-separated font stack', function (done) {
supertest(app)
.get('/fonts/Open%20Sans%20Bold%2COpen%20Sans%20Regular/0-255.pbf')
.expect(200)
.expect('Content-Type', /application\/x-protobuf/, done);
});
});

describe('304 Not Modified caching', function () {
it('returns 304 when If-Modified-Since matches Last-Modified', function (done) {
supertest(app)
.get('/fonts/Open%20Sans%20Bold/0-255.pbf')
.end(function (err, res) {
if (err) return done(err);
const lastModified = res.headers['last-modified'];
supertest(app)
.get('/fonts/Open%20Sans%20Bold/0-255.pbf')
.set('If-Modified-Since', lastModified)
.expect(304, done);
});
});

it('returns 200 when Cache-Control: no-cache overrides If-Modified-Since', function (done) {
supertest(app)
.get('/fonts/Open%20Sans%20Bold/0-255.pbf')
.end(function (err, res) {
if (err) return done(err);
const lastModified = res.headers['last-modified'];
supertest(app)
.get('/fonts/Open%20Sans%20Bold/0-255.pbf')
.set('If-Modified-Since', lastModified)
.set('Cache-Control', 'no-cache')
.expect(200, done);
});
});
});

describe('invalid requests return 400', function () {
it('returns 400 for fully nonexistent font', function (done) {
supertest(app)
.get('/fonts/Nonsense/0-255.pbf')
.expect(400, done);
});

it('returns 400 when all fonts in stack are nonexistent', function (done) {
supertest(app)
.get('/fonts/Nonsense1%2CNonsense2/0-255.pbf')
.expect(400, done);
});

it('returns 400 when first font in stack is nonexistent', function (done) {
supertest(app)
.get('/fonts/Nonsense%2COpen%20Sans%20Bold/0-255.pbf')
.expect(400, done);
});
});
});
});
160 changes: 160 additions & 0 deletions test/style_urls.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
const prefix = 'test-style';
const styleUrl = '/styles/' + prefix + '/style.json';

describe('Style URL rewriting', function () {
describe('sprite URL', function () {
it('is rewritten to absolute URL', function (done) {
supertest(app)
.get(styleUrl)
.expect(function (res) {
expect(res.body.sprite).to.match(/^http/);
})
.end(done);
});

it('contains correct style id path', function (done) {
supertest(app)
.get(styleUrl)
.expect(function (res) {
expect(res.body.sprite).to.include('/styles/' + prefix + '/sprite');
})
.end(done);
});
});

describe('glyphs URL', function () {
it('is rewritten to absolute URL', function (done) {
supertest(app)
.get(styleUrl)
.expect(function (res) {
expect(res.body.glyphs).to.match(/^http/);
})
.end(done);
});

it('preserves {fontstack} and {range} template placeholders', function (done) {
supertest(app)
.get(styleUrl)
.expect(function (res) {
expect(res.body.glyphs).to.include('{fontstack}');
expect(res.body.glyphs).to.include('{range}');
})
.end(done);
});
});

describe('source URLs', function () {
it('all source tile URLs are absolute', function (done) {
supertest(app)
.get(styleUrl)
.expect(function (res) {
for (const name of Object.keys(res.body.sources)) {
const source = res.body.sources[name];
if (source.url) {
expect(source.url).to.match(/^http/);
}
}
})
.end(done);
});
});
});

describe('styles.json listing', function () {
it('each item has an absolute url field', function (done) {
supertest(app)
.get('/styles.json')
.expect(function (res) {
for (const item of res.body) {
expect(item.url).to.match(/^http/);
expect(item.url).to.include('/styles/');
expect(item.url).to.include('/style.json');
}
})
.end(done);
});

it('contains both configured styles', function (done) {
supertest(app)
.get('/styles.json')
.expect(function (res) {
const ids = res.body.map((s) => s.id);
expect(ids).to.include('test-style');
expect(ids).to.include('maptiler-basic');
})
.end(done);
});
});

describe('Rendered TileJSON', function () {
it('/styles/' + prefix + '.json has tileSize 256 by default', function (done) {
supertest(app)
.get('/styles/' + prefix + '.json')
.expect(200)
.expect(function (res) {
expect(res.body.tileSize).to.equal(256);
expect(res.body.tiles).to.be.a('array');
expect(res.body.tiles[0]).to.match(/^http/);
})
.end(done);
});

it('/styles/512/' + prefix + '.json has tileSize 512', function (done) {
supertest(app)
.get('/styles/512/' + prefix + '.json')
.expect(200)
.expect(function (res) {
expect(res.body.tileSize).to.equal(512);
expect(res.body.tiles[0]).to.include('/512/');
})
.end(done);
});

it('/styles/non_existent.json returns 404', function (done) {
supertest(app).get('/styles/non_existent.json').expect(404, done);
});
});

describe('Listing endpoints content', function () {
describe('/rendered.json', function () {
it('items have absolute tile URLs', function (done) {
supertest(app)
.get('/rendered.json')
.expect(function (res) {
for (const item of res.body) {
expect(item.tiles[0]).to.match(/^http/);
}
})
.end(done);
});
});

describe('/data.json', function () {
it('contains configured data sources', function (done) {
supertest(app)
.get('/data.json')
.expect(function (res) {
const names = res.body.map((d) => d.name || d.id);
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
expect(res.body.length).to.be.greaterThan(0);
})
.end(done);
});

it('items have absolute tile URLs', function (done) {
supertest(app)
.get('/data.json')
.expect(function (res) {
for (const item of res.body) {
expect(item.tiles[0]).to.match(/^http/);
}
})
.end(done);
});
});
});

describe('Health endpoint', function () {
it('returns OK body when server is up', function (done) {
supertest(app).get('/health').expect(200).expect('OK', done);
});
});
72 changes: 69 additions & 3 deletions test/tiles_data.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
const testTile = function (prefix, z, x, y, status) {
const path = '/data/' + prefix + '/' + z + '/' + x + '/' + y + '.pbf';
const testTile = function (prefix, z, x, y, status, format = 'pbf') {
const path = '/data/' + prefix + '/' + z + '/' + x + '/' + y + '.' + format;
it(path + ' returns ' + status, function (done) {
const test = supertest(app).get(path);
if (status) test.expect(status);
if (status == 200) test.expect('Content-Type', /application\/x-protobuf/);
if (status === 200 && format === 'pbf')
test.expect('Content-Type', /application\/x-protobuf/);
if (status === 200 && format === 'geojson')
test.expect('Content-Type', /application\/json/);
test.end(done);
});
};
Expand All @@ -25,4 +28,67 @@ describe('Vector tiles', function () {

testTile(prefix, 14, 0, 0, 204); // non existent tile (vector tiles default to 204)
});

describe('GeoJSON format', function () {
it('/data/' + prefix + '/14/8581/5738.geojson returns 200 with GeoJSON', function (done) {
supertest(app)
.get('/data/' + prefix + '/14/8581/5738.geojson')
.expect(200)
.expect('Content-Type', /application\/json/)
.expect(function (res) {
expect(res.body.type).to.equal('FeatureCollection');
expect(res.body.features).to.be.a('array');
})
.end(done);
});

it('/data/' + prefix + '/0/0/0.geojson returns 200 with GeoJSON', function (done) {
supertest(app)
.get('/data/' + prefix + '/0/0/0.geojson')
.expect(200)
.expect('Content-Type', /application\/json/)
.expect(function (res) {
expect(res.body.type).to.equal('FeatureCollection');
})
.end(done);
});

it('returns 404 for invalid format on vector source', function (done) {
supertest(app)
.get('/data/' + prefix + '/0/0/0.png')
.expect(404, done);
});
});
});

describe('Data TileJSON', function () {
it('/data/' + prefix + '.json returns 200 with TileJSON', function (done) {
supertest(app)
.get('/data/' + prefix + '.json')
.expect(200)
.expect('Content-Type', /application\/json/)
.expect(function (res) {
expect(res.body.tiles).to.be.a('array');
expect(res.body.tiles.length).to.be.greaterThan(0);
expect(res.body.minzoom).to.be.a('number');
expect(res.body.maxzoom).to.be.a('number');
expect(res.body.format).to.be.a('string');
})
.end(done);
});

it('/data/' + prefix + '.json tile URLs are absolute', function (done) {
supertest(app)
.get('/data/' + prefix + '.json')
.expect(function (res) {
const tileUrl = res.body.tiles[0];
expect(tileUrl).to.match(/^http/);
expect(tileUrl).to.include(prefix);
})
.end(done);
});

it('/data/non_existent.json returns 404', function (done) {
supertest(app).get('/data/non_existent.json').expect(404, done);
});
});
Loading
Loading