UNPKG

terriajs

Version:

Geospatial data visualization platform.

396 lines (371 loc) 23.3 kB
'use strict'; /*global require, fail*/ var loadText = require('../../lib/Core/loadText'); var Rectangle = require('terriajs-cesium/Source/Core/Rectangle'); var when = require('terriajs-cesium/Source/ThirdParty/when'); var Terria = require('../../lib/Models/Terria'); var SdmxJsonCatalogItem = require('../../lib/Models/SdmxJsonCatalogItem'); describe('SdmxJsonCatalogItem', function() { var terria; var item; beforeEach(function() { terria = new Terria({ baseUrl: './' }); item = new SdmxJsonCatalogItem(terria); }); it('can update from json', function() { item.updateFromJson({ name: 'Name', description: 'Description', rectangle: [-10, 10, -20, 20], url: 'http://foo.bar', dataUrlComponent: 'atad' }); expect(item.name).toBe('Name'); expect(item.description).toBe('Description'); expect(item.rectangle).toEqual(Rectangle.fromDegrees(-10, 10, -20, 20)); expect(item.type).toBe('sdmx-json'); expect(item.url.indexOf('http://foo.bar')).toBe(0); expect(item.dataUrlComponent).toBe('atad'); }); it('can be round-tripped with serializeToJson and updateFromJson', function() { item.updateFromJson({ name: 'Name', id: 'Id', description: 'Description', rectangle: [-10, 10, -20, 20], url: 'http://foo.bar/', dataUrlComponent: 'atad' }); var json = item.serializeToJson(); // This json should include selectedInitially. expect(json.selectedInitially).toBeDefined(); var reconstructed = new SdmxJsonCatalogItem(terria); reconstructed.updateFromJson(json); // item.concepts has a circular dependency via its __knockoutSubscribable property, // with itself being a subscriber, so it will not equal reconstructed.concepts. // So check the arrays are equal, and then remove them before comparing the rest of the item. expect(item.concepts.slice(), reconstructed.concepts.slice()); delete item.concepts; delete item._concepts; delete reconstructed.concepts; delete reconstructed._concepts; // for (var i = Object.keys(item).length - 1; i >= 0; i--) { // var k = Object.keys(item)[i]; // console.log(k); // expect(reconstructed[k]).toEqual(item[k]); // } expect(reconstructed.name).toEqual(item.name); expect(reconstructed.id).toEqual(item.id); expect(reconstructed.description).toEqual(item.description); expect(reconstructed.rectangle).toEqual(item.rectangle); expect(reconstructed.url).toEqual(item.url); expect(reconstructed.dataUrlComponent).toEqual(item.dataUrlComponent); }); describe('loading', function() { var regionMappingJson, lga13Data, steData; var dataflowFoo, dataFoo, dataFooBD2, dataFooBD2t, dataFoo2, dataNonSpatial, dataAsObs, dataAsObsRepeated, dataNoSteYear; beforeEach(function(done) { when.all([ loadText('test/SDMX-JSON/dataflow-foo.json').then(function(text) { dataflowFoo = text; }), loadText('test/SDMX-JSON/data-foo-2013.json').then(function(text) { dataFoo = text; }), loadText('test/SDMX-JSON/data-foo-BD2-2013.json').then(function(text) { dataFooBD2 = text; }), loadText('test/SDMX-JSON/data-foo-BD2-2011_2013.json').then(function(text) { dataFooBD2t = text; }), loadText('test/SDMX-JSON/data-foo2-2013.json').then(function(text) { dataFoo2 = text; }), loadText('test/SDMX-JSON/data-nonspatial.json').then(function(text) { dataNonSpatial = text; }), loadText('test/SDMX-JSON/data-as-observations.json').then(function(text) { dataAsObs = text; }), loadText('test/SDMX-JSON/data-ste-no-year.json').then(function(text) { dataNoSteYear = text; }), loadText('test/SDMX-JSON/data-as-obs-repeated-dim.json').then(function(text) { dataAsObsRepeated = text; }), loadText('data/regionMapping.json').then(function(text) { regionMappingJson = text; }), loadText('data/regionids/region_map-FID_LGA_2013_AUST_LGA_CODE13.json').then(function(text) { lga13Data = text; }), loadText('data/regionids/region_map-FID_STE_2011_AUST_STE_CODE11.json').then(function(text) { steData = text; }) ]).then(function() { jasmine.Ajax.install(); jasmine.Ajax.stubRequest(/.*/).andError(); // Fail all requests by default. jasmine.Ajax.stubRequest('http://sdmx.example.com/sdmx-json/dataflow/FOO').andReturn({ responseText: dataflowFoo }); jasmine.Ajax.stubRequest('http://sdmx.example.com/sdmx-json/data/FOO/BD_2+BD_4.LGA_2013..A/all?startTime=2013&endTime=2013').andReturn({ responseText: dataFoo }); jasmine.Ajax.stubRequest('http://sdmx.example.com/sdmx-json/data/FOO/BD_2.LGA_2013..A/all?startTime=2013&endTime=2013').andReturn({ responseText: dataFooBD2 }); jasmine.Ajax.stubRequest('http://sdmx.example.com/sdmx-json/data/FOO/BD_2.LGA_2013..A/all?startTime=2011&endTime=2013').andReturn({ responseText: dataFooBD2t }); jasmine.Ajax.stubRequest('http://sdmx.example.com/sdmx-json/data/FOO2/BD_2+BD_4..A../all?startTime=2013&endTime=2013').andReturn({ responseText: dataFoo2 }); jasmine.Ajax.stubRequest('http://sdmx.example.com/sdmx-json/data/NONSPATIAL/all/all').andReturn({ responseText: dataNonSpatial }); jasmine.Ajax.stubRequest('http://sdmx.example.com/sdmx-json/data/FOO-OBS/./all').andReturn({ responseText: dataAsObs }); jasmine.Ajax.stubRequest('http://sdmx.example.com/sdmx-json/data/FOO-STE-NO-YEAR/./all').andReturn({ responseText: dataNoSteYear }); jasmine.Ajax.stubRequest('http://sdmx.example.com/sdmx-json/data/FOO-OBS-RPT/./all').andReturn({ responseText: dataAsObsRepeated }); jasmine.Ajax.stubRequest('data/regionMapping.json').andReturn({ responseText: regionMappingJson }); jasmine.Ajax.stubRequest('data/regionids/region_map-FID_LGA_2013_AUST_LGA_CODE13.json').andReturn({ responseText: lga13Data }); jasmine.Ajax.stubRequest('data/regionids/region_map-FID_STE_2011_AUST_STE_CODE11.json').andReturn({ responseText: steData }); }).then(done).otherwise(done.fail); }); afterEach(function() { jasmine.Ajax.uninstall(); }); it('works with a simple file', function(done) { item.updateFromJson({ name: 'Foo', url: 'http://sdmx.example.com/sdmx-json/data/FOO/BD_2.LGA_2013..A/all?startTime=2013&endTime=2013' }); item.load().then(function() { // Expect it to have realised this is regional data. var regionDetails = item.regionMapping.regionDetails; expect(regionDetails).toBeDefined(); // Expect it to have created the right table of data (with no time dimension). var columnNames = item.tableStructure.getColumnNames(); expect(columnNames.length).toEqual(3); expect(columnNames[1]).toEqual('LGA_code_2013'); // Test a "slice" of the column's values, to remove knockout stuff. expect(item.tableStructure.columns[0].values.slice()).toEqual(['2013', '2013', '2013', '2013', '2013']); expect(item.tableStructure.columns[1].values.slice()).toEqual(['17100', '56520', '54970', '10300', '29399']); expect(item.tableStructure.columns[2].values.slice()).toEqual([1140, 535, 79, 12, 38]); // Expect it not to show any concepts to the user. expect(item.concepts.length).toEqual(0); }).otherwise(fail).then(done); }); it('works with a two-concept file', function(done) { item.updateFromJson({ name: 'Foo2', url: 'http://sdmx.example.com/sdmx-json/data/FOO2/BD_2+BD_4..A../all?startTime=2013&endTime=2013' }); item.load().then(function() { // Expect it to have realised this is regional data. var regionDetails = item.regionMapping.regionDetails; expect(regionDetails).toBeDefined(); // Expect it to have created the right table of data (with a time dimension). var columnNames = item.tableStructure.getColumnNames(); expect(columnNames.length).toEqual(7); expect(columnNames[1]).toEqual('LGA_code_2013'); expect(item.tableStructure.columns[0].values.slice()).toEqual(['2013', '2013', '2013', '2013', '2013']); expect(item.tableStructure.columns[1].values.slice()).toEqual(['17100', '56520', '54970', '10300', '29399']); expect(item.tableStructure.columns[2].values.slice()).toEqual([1140, 535, 79, 12, 38]); expect(item.tableStructure.columns[3].values.slice()).toEqual([2140, 2535, 2179, 2112, 2138]); expect(item.tableStructure.columns[4].values.slice()).toEqual([140, 35, 179, 112, 138]); expect(item.tableStructure.columns[5].values.slice()).toEqual([1140, 1035, 579, 1512, 2138]); expect(item.tableStructure.columns[6].values.slice()).toEqual([1140, 535, 79, 12, 38]); // Expect it to show 2 concepts to the user, each with 2 sub items. var conceptItems = item.concepts[0].items; expect(conceptItems.length).toEqual(2); expect(conceptItems[0].items.length).toEqual(2); expect(conceptItems[1].items.length).toEqual(2); }).otherwise(fail).then(done); }); it('works with a generic endpoint', function(done) { item.updateFromJson({ name: 'Foo', url: 'http://sdmx.example.com/sdmx-json/data/FOO', startTime: '2013', endTime: '2013' }); item.load().then(function() { // Expect it to have realised this is regional data. var regionDetails = item.regionMapping.regionDetails; expect(regionDetails).toBeDefined(); // Expect it to have created the right table of data (with a time dimension). var columnNames = item.tableStructure.getColumnNames(); expect(columnNames.length).toEqual(4); // It shows a single concept and so always shows a total column. expect(columnNames[1]).toEqual('LGA_code_2013'); expect(item.tableStructure.columns[0].values.slice()).toEqual(['2013', '2013', '2013', '2013', '2013']); expect(item.tableStructure.columns[1].values.slice()).toEqual(['17100', '56520', '54970', '10300', '29399']); expect(item.tableStructure.columns[2].values.slice()).toEqual([1140, 535, 79, 12, 38]); expect(item.tableStructure.columns[3].values.slice()).toEqual(item.tableStructure.columns[2].values.slice()); // Expect it to show the birth/death concept to the user. var conceptItems = item.concepts[0].items; expect(conceptItems.length).toEqual(1); }).otherwise(fail).then(done); }); it('works with selectedInitially on a generic endpoint', function(done) { item.updateFromJson({ name: 'Foo', url: 'http://sdmx.example.com/sdmx-json/data/FOO', startTime: '2013', endTime: '2013', selectedInitially: { 'MEASURE': ['BD_2', 'BD_4'] } }); item.load().then(function() { // Expect it to have realised this is regional data. var regionDetails = item.regionMapping.regionDetails; expect(regionDetails).toBeDefined(); // Expect it to have created the right table of data (with a time dimension). var columnNames = item.tableStructure.getColumnNames(); expect(columnNames.length).toEqual(5); // Region, BD_2, BD_4 and a total. expect(columnNames[1]).toEqual('LGA_code_2013'); expect(item.tableStructure.columns[0].values.slice()).toEqual(['2013', '2013', '2013', '2013', '2013']); expect(item.tableStructure.columns[1].values.slice()).toEqual(['17100', '56520', '54970', '10300', '29399']); expect(item.tableStructure.columns[2].values.slice()).toEqual([1140, 535, 79, 12, 38]); expect(item.tableStructure.columns[3].values.slice()).toEqual([140, 235, 279, 812, 338]); expect(item.tableStructure.columns[4].values.slice()).toEqual([1280, 770, 358, 824, 376]); // Expect it to show the birth/death concept to the user. var conceptItems = item.concepts[0].items; expect(conceptItems.length).toEqual(1); }).otherwise(fail).then(done); }); it('works with invalid selectedInitially', function(done) { item.updateFromJson({ name: 'Foo', url: 'http://sdmx.example.com/sdmx-json/data/FOO', startTime: '2013', endTime: '2013', selectedInitially: { 'MEASURE': ['NO_THERE', 'NOT_HERE_EITHER'] } }); item.load().then(function() { // Expect it to have realised this is regional data. var regionDetails = item.regionMapping.regionDetails; expect(regionDetails).toBeDefined(); // Expect it to have created the right table of data (with a time dimension). var columnNames = item.tableStructure.getColumnNames(); expect(columnNames.length).toEqual(4); // Region, only one BD and a total. // Expect the bad selectedInitially setting to be wiped out. expect(item.selectedInitially.MEASURE).not.toBeDefined(); }).otherwise(fail).then(done); }); it('works with cannotSum', function(done) { item.updateFromJson({ name: 'Foo', url: 'http://sdmx.example.com/sdmx-json/data/FOO', startTime: '2013', endTime: '2013', selectedInitially: { 'MEASURE': ['BD_2', 'BD_4'] }, cannotSum: { 'MEASURE': ['BD_2'] } }); item.load().then(function() { // Expect it to have realised this is regional data. var regionDetails = item.regionMapping.regionDetails; expect(regionDetails).toBeDefined(); // Expect it to have created the right table of data (with a time dimension) - crucially, without a total. var columnNames = item.tableStructure.getColumnNames(); expect(columnNames.slice()).toEqual(['date', 'LGA_code_2013', 'Births', 'Deaths']); // No total. }).otherwise(fail).then(done); }); it('works with a time-varying file', function(done) { item.updateFromJson({ name: 'Foo', url: 'http://sdmx.example.com/sdmx-json/data/FOO/BD_2.LGA_2013..A/all?startTime=2011&endTime=2013' }); item.load().then(function() { // Expect it to have realised this is regional data. var regionDetails = item.regionMapping.regionDetails; expect(regionDetails).toBeDefined(); // Expect it to have created the right table of data (with a time dimension). var columnNames = item.tableStructure.getColumnNames(); expect(columnNames.length).toEqual(3); expect(columnNames[0]).toEqual('date'); expect(columnNames[1]).toEqual('LGA_code_2013'); expect(item.tableStructure.columns[0].values.length).toEqual(5 * 3); // 5 regions x 3 dates. // Expect it not to show any concepts to the user. expect(item.concepts.length).toEqual(0); }).otherwise(fail).then(done); }); it('recognizes non-spatial data', function(done) { item.updateFromJson({ name: 'NonSpatial', url: 'http://sdmx.example.com/sdmx-json/data/NONSPATIAL/all/all' }); item.load().then(function() { // Expect it to have realised this has NO regional data. var regionDetails = item.regionMapping.regionDetails; expect(regionDetails).not.toBeDefined(); // Beyond this, assume nothing. But if you want it to work, you may want the following: // expect(item.isMappable).toBe(false); // // Expect it to have created the right table of data (with no time dimension). // var columnNames = item.tableStructure.getColumnNames(); // expect(columnNames.length).toEqual(2 + 5 * 2 * 2); // one for each value, plus date and total columns. // expect(item.tableStructure.columns[0].values.length).toEqual(3); // 3 dates. // // Expect it to show 3 concepts to the user. // var conceptItems = item.concepts[0].items; // expect(conceptItems.length).toEqual(3); }).otherwise(fail).then(done); }); it('works with a data provided as observations not series', function(done) { item.updateFromJson({ name: 'Foo', url: 'http://sdmx.example.com/sdmx-json/data/FOO-OBS/./all' }); item.load().then(function() { // Expect it to have realised this is regional data. var regionDetails = item.regionMapping.regionDetails; expect(regionDetails).toBeDefined(); // Expect it to have created the right table of data (with a time dimension). var columnNames = item.tableStructure.getColumnNames(); expect(columnNames.length).toEqual(3); expect(columnNames[0]).toEqual('date'); expect(columnNames[1]).toEqual('STE_code_2011'); expect(item.tableStructure.columns[0].values.slice()).toEqual(['2001', '2001', '2001', '2001', '2001', '2001', '2001', '2001', '2001']); expect(item.tableStructure.columns[1].values.slice()).toEqual(['1', '2', '3', '4', '5', '6', '7', '8', '9']); expect(item.tableStructure.columns[2].values.slice()).toEqual([17658, 14042, 9739, 6572, 2970, 4940, 945, 7222, 13001]); // Expect it not to show any concepts to the user. expect(item.concepts.length).toEqual(0); }).otherwise(fail).then(done); }); it('can apply a template to the region column name', function(done) { // This is the same data as the previous spec, but now we add `regionNameTemplate: "{{name}}_code_2016"` item.updateFromJson({ name: 'Foo', regionNameTemplate: "{{name}}_code_2011", url: 'http://sdmx.example.com/sdmx-json/data/FOO-STE-NO-YEAR/./all' }); item.load().then(function() { // Expect it to have realised this is regional data. var regionDetails = item.regionMapping.regionDetails; expect(regionDetails).toBeDefined(); // Expect it to have appended to regionYear to the region column, per csv-geo-au. var columnNames = item.tableStructure.getColumnNames(); expect(columnNames[1]).toEqual('STE_code_2011'); }).otherwise(fail).then(done); }); it('works with an aggregated dimension', function(done) { item.updateFromJson({ name: 'Foo', url: 'http://sdmx.example.com/sdmx-json/data/FOO-OBS-RPT/./all', aggregatedDimensionIds: ['STATE'] }); item.load().then(function() { // Expect it to have realised this is regional data. var regionDetails = item.regionMapping.regionDetails; expect(regionDetails).toBeDefined(); // Expect it to have created the right table of data (with a time dimension). var columnNames = item.tableStructure.getColumnNames(); expect(columnNames.length).toEqual(3); expect(columnNames[0]).toEqual('date'); expect(columnNames[1]).toEqual('STE_code_2011'); expect(item.tableStructure.columns[0].values.slice()).toEqual(['2001', '2001', '2001', '2001', '2001', '2001', '2001', '2001', '2001']); expect(item.tableStructure.columns[1].values.slice()).toEqual(['1', '2', '3', '4', '5', '6', '7', '8', '9']); // Expect it to have aggregated up the data across the STATE dimension. expect(item.tableStructure.columns[2].values.slice()).toEqual([17658, 14042, 9739, 6572, 2970, 4940, null, 1945, 13001]); // Expect it not to show any concepts to the user. expect(item.concepts.length).toEqual(0); }).otherwise(fail).then(done); }); // I'm not sure we want this test. it('gracefully handles a non-SDMX URL', function(done) { item.updateFromJson({ name: 'Name', url: 'http://example.com' }); item.load().then(function() { return item.dataSource.regionPromise; }).otherwise(function(e) { // We actually want this to fail; if it doesn't get here, will say SPEC HAS NO EXPECTATIONS. expect(true).toBe(true); }).then(done); }); it('is less than 2000 characters when serialised to JSON then URLEncoded', function(done) { item.updateFromJson({ name: 'Name', description: 'Description', url: 'http://abs.example.com/', dataUrlComponent: 'foo' }); item.load().then(function() { var url = encodeURIComponent(JSON.stringify(item.serializeToJson())); expect(url.length).toBeLessThan(2000); }).otherwise(fail).then(done); }); }); });