├── .eslintrc ├── .gitignore ├── .npmrc ├── Procfile ├── README.md ├── app ├── __mocks__ │ └── photo_model.js ├── __tests__ │ ├── app.test.js │ ├── form_validator.test.js │ ├── jsonp_helper.test.js │ └── photo_model.test.js ├── form_validator.js ├── jsonp_helper.js ├── photo_model.js ├── public │ ├── css │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ ├── bootstrap.min.css │ │ └── style.css │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ └── glyphicons-halflings-regular.woff │ └── images │ │ └── favicon.ico ├── route.js ├── server.js └── views │ ├── _footer.html │ ├── _header.html │ ├── _search_form.html │ ├── _search_results.html │ └── index.html ├── coverage ├── clover.xml ├── coverage-final.json ├── lcov-report │ ├── app.js.html │ ├── base.css │ ├── block-navigation.js │ ├── favicon.png │ ├── form_validator.js.html │ ├── index.html │ ├── jsonp_helper.js.html │ ├── photo_model.js.html │ ├── prettify.css │ ├── prettify.js │ ├── route.js.html │ ├── server.js.html │ ├── sort-arrow-sprite.png │ └── sorter.js └── lcov.info ├── e2e_tests └── flickr_public_feed_api.test.js ├── package-lock.json └── package.json /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "env": { 4 | "node": true, 5 | "es6": true 6 | }, 7 | "parserOptions": { 8 | "ecmaVersion": 6 9 | }, 10 | "globals": { 11 | "jest": false, 12 | "expect": false, 13 | "describe": false, 14 | "test": false, 15 | "beforeAll": false, 16 | "beforeEach": false, 17 | "afterAll": false, 18 | "afterEach": false 19 | }, 20 | "rules": { 21 | "no-console": "off" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log* 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmjs.org/ 2 | save=true 3 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: node app/server.js 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # express-app-testing-demo 2 | 3 | This project is a simple express app for demonstrating testing and code coverage. 4 | [Jest](https://facebook.github.io/jest/) and 5 | [Supertest](https://github.com/visionmedia/supertest) are used for testing. 6 | Jest is also used for mocking functions and measuring code coverage. 7 | Note that this app only focuses on server-side JavaScript testing. 8 | 9 | 10 | ## Requirements 11 | 12 | * Node.js - [https://nodejs.org/](https://nodejs.org/) 13 | 14 | 15 | ## Getting Started 16 | 17 | * Clone the repo 18 | * Install dependencies with `npm install` 19 | * Run server with `npm start` and go here: 20 | [http://localhost:3000/](http://localhost:3000/) 21 | 22 | 23 | ## Running Tests 24 | 25 | * Run unit and integration tests: `npm test` 26 | * Run end-to-end tests: `npm run test:e2e` 27 | 28 | ## Code Coverage Report 29 | 30 | A new code coverage report is generated every time `npm test` runs. 31 | Normally this coverage report is ignored by git. 32 | This project includes it in source control so the coverage report can be viewed in the demo app: 33 | [http://express-app-testing-demo.herokuapp.com/coverage/lcov-report/index.html](http://express-app-testing-demo.herokuapp.com/coverage/lcov-report/index.html) 34 | -------------------------------------------------------------------------------- /app/__mocks__/photo_model.js: -------------------------------------------------------------------------------- 1 | function getFlickrPhotos(tags) { 2 | if (tags === 'error') { 3 | return Promise.reject('Internal server error'); 4 | } 5 | 6 | return Promise.resolve([ 7 | { 8 | title: 'Point Lobos sunset', 9 | link: 'http://www.flickr.com/photos/nathanleefer/24437997081/', 10 | media: { 11 | m: 'http://farm2.staticflickr.com/1566/24437997081_a18e803502_m.jpg', 12 | t: 'http://farm2.staticflickr.com/1566/24437997081_a18e803502_t.jpg', 13 | b: 'http://farm2.staticflickr.com/1566/24437997081_a18e803502_b.jpg' 14 | }, 15 | date_taken: '2013-09-21T19:02:39-08:00', 16 | description: 17 | '

' + 18 | 'nathan.leefer posted a photo

', 19 | published: '2016-01-21T14:45:43Z', 20 | author: 'nobody@flickr.com ("nathan.leefer")', 21 | author_id: '127138564@N02', 22 | tags: 'sunsetcalifornia pointlobospacificoceanmontereycarmelbigsur' 23 | } 24 | ]); 25 | } 26 | 27 | module.exports = { 28 | getFlickrPhotos 29 | }; 30 | -------------------------------------------------------------------------------- /app/__tests__/app.test.js: -------------------------------------------------------------------------------- 1 | const request = require('supertest'); 2 | 3 | jest.mock('../../app/photo_model'); 4 | const app = require('../../app/server'); 5 | 6 | describe('index route', () => { 7 | afterEach(() => { 8 | app.server.close(); 9 | }); 10 | 11 | test('should respond with a 200 with no query parameters', () => { 12 | return request(app) 13 | .get('/') 14 | .expect('Content-Type', /html/) 15 | .expect(200) 16 | .then(response => { 17 | expect(response.text).toMatch( 18 | /Express App Testing Demo<\/title>/ 19 | ); 20 | }); 21 | }); 22 | 23 | test('should respond with a 200 with valid query parameters', () => { 24 | return request(app) 25 | .get('/?tags=california&tagmode=all') 26 | .expect('Content-Type', /html/) 27 | .expect(200) 28 | .then(response => { 29 | expect(response.text).toMatch( 30 | /<div class="panel panel-default search-results">/ 31 | ); 32 | }); 33 | }); 34 | 35 | test('should respond with a 200 with invalid query parameters', () => { 36 | return request(app) 37 | .get('/?tags=california123&tagmode=all') 38 | .expect('Content-Type', /html/) 39 | .expect(200) 40 | .then(response => { 41 | expect(response.text).toMatch(/<div class="alert alert-danger">/); 42 | }); 43 | }); 44 | 45 | test('should respond with a 500 error due to bad jsonp data', () => { 46 | return request(app) 47 | .get('/?tags=error&tagmode=all') 48 | .expect('Content-Type', /json/) 49 | .expect(500) 50 | .then(response => { 51 | expect(response.body).toEqual({ error: 'Internal server error' }); 52 | }); 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /app/__tests__/form_validator.test.js: -------------------------------------------------------------------------------- 1 | const formValidator = require('../../app/form_validator'); 2 | 3 | describe('isValidCommaDelimitedList(value)', () => { 4 | test('should return true for valid list of search terms', () => { 5 | const tags = 'california, sunset, red'; 6 | expect(formValidator.isValidCommaDelimitedList(tags)).toBe(true); 7 | }); 8 | 9 | test('should return true for valid single search term', () => { 10 | const tags = 'dogs'; 11 | expect(formValidator.isValidCommaDelimitedList(tags)).toBe(true); 12 | }); 13 | 14 | test('should return false for search term containing numbers', () => { 15 | const tags = 'dogs123'; 16 | expect(formValidator.isValidCommaDelimitedList(tags)).toBe(false); 17 | }); 18 | 19 | test('should return false for search term containing special characters', () => { 20 | const tags = 'dogs%$'; 21 | expect(formValidator.isValidCommaDelimitedList(tags)).toBe(false); 22 | }); 23 | }); 24 | 25 | describe('isValidTagmode(value)', () => { 26 | test('should return true for valid tagmode "any"', () => { 27 | const tagmode = 'any'; 28 | expect(formValidator.isValidTagmode(tagmode)).toBe(true); 29 | }); 30 | 31 | test('should return true for valid tagmode "all"', () => { 32 | const tagmode = 'all'; 33 | expect(formValidator.isValidTagmode(tagmode)).toBe(true); 34 | }); 35 | 36 | test('should return false for invalid tagmode', () => { 37 | const tagmode = 'many'; 38 | expect(formValidator.isValidTagmode(tagmode)).toBe(false); 39 | }); 40 | }); 41 | 42 | describe('hasValidFlickrAPIParams(tags, tagmode)', () => { 43 | test('should return true for valid params', () => { 44 | const tags = 'dogs, poodles'; 45 | const tagmode = 'all'; 46 | expect(formValidator.hasValidFlickrAPIParams(tags, tagmode)).toBe(true); 47 | }); 48 | 49 | test('should return false for invalid tags', () => { 50 | const tags = 'dogs, poodles123'; 51 | const tagmode = 'all'; 52 | expect(formValidator.hasValidFlickrAPIParams(tags, tagmode)).toBe(false); 53 | }); 54 | 55 | test('should return false for invalid tagmode', () => { 56 | const tags = 'dogs, poodles'; 57 | const tagmode = 'all123'; 58 | expect(formValidator.hasValidFlickrAPIParams(tags, tagmode)).toBe(false); 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /app/__tests__/jsonp_helper.test.js: -------------------------------------------------------------------------------- 1 | const jsonpHelper = require('../../app/jsonp_helper'); 2 | 3 | describe('parseJSONP(jsonpData)', () => { 4 | test('should parse valid jsonp data', () => { 5 | const jsonpData = 'jsonFlickrFeed({"title": "tagged california"});'; 6 | const jsObject = jsonpHelper.parseJSONP(jsonpData); 7 | expect(jsObject).toMatchObject({ 8 | title: 'tagged california' 9 | }); 10 | }); 11 | 12 | test('should parse jsonp data with escaped single quotes', () => { 13 | const jsonpData = 14 | 'jsonFlickrFeed({"title": "tagged california\'s coast"});'; 15 | const jsObject = jsonpHelper.parseJSONP(jsonpData); 16 | expect(jsObject).toMatchObject({ 17 | title: "tagged california's coast" 18 | }); 19 | }); 20 | 21 | test('should throw error when parsing invalid jsonp data', () => { 22 | // invalid json because of missing double quotes around title value 23 | const jsonpData = 'jsonFlickrFeed({"title": tagged california});'; 24 | 25 | expect(function() { 26 | // call the add(item) method without passing in an item 27 | jsonpHelper.parseJSONP(jsonpData); 28 | }).toThrowError(/Failed to convert jsonp to json/); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /app/__tests__/photo_model.test.js: -------------------------------------------------------------------------------- 1 | let photoModel; 2 | 3 | describe('getFlickrPhotos(tags, tagmode, callback)', () => { 4 | beforeEach(() => { 5 | jest.resetModules(); 6 | }); 7 | 8 | test('should return photos', () => { 9 | // mock the flickr public feed api endpoint 10 | jest.doMock('got', () => { 11 | return jest.fn(() => { 12 | const jsonpData = `jsonFlickrFeed({ 13 | "items": [ 14 | { 15 | "title": "Boating", 16 | "media": { 17 | "m": "http://farm4.staticflickr.com/3727/12608622365_9e9b8b377d_m.jpg" 18 | } 19 | }, 20 | { 21 | "title": "Signs", 22 | "media": { 23 | "m": "http://farm8.staticflickr.com/7446/12608714423_efaf73400c_m.jpg" 24 | } 25 | } 26 | ] 27 | })`; 28 | return Promise.resolve({ 29 | body: jsonpData 30 | }); 31 | }); 32 | }); 33 | 34 | photoModel = require('../../app/photo_model'); 35 | 36 | const expectedSubset = [ 37 | { 38 | title: 'Boating', 39 | media: { 40 | t: expect.stringMatching(/t.jpg/), 41 | m: expect.stringMatching(/m.jpg/), 42 | b: expect.stringMatching(/b.jpg/) 43 | } 44 | } 45 | ]; 46 | 47 | return photoModel.getFlickrPhotos('california', 'all').then(photos => { 48 | expect(photos).toEqual(expect.arrayContaining(expectedSubset)); 49 | }); 50 | }); 51 | 52 | test('should error when api returns 500 http status code', () => { 53 | // mock the flickr public feed api endpoint and return a 500 error 54 | jest.doMock('got', () => { 55 | return jest.fn(() => { 56 | return Promise.reject('Response code 500 (Internal Server Error)'); 57 | }); 58 | }); 59 | 60 | photoModel = require('../../app/photo_model'); 61 | 62 | return photoModel.getFlickrPhotos('california', 'all').catch(error => { 63 | expect(error.toString()).toMatch(/Response code 500/); 64 | }); 65 | }); 66 | 67 | test('should error with invalid jsonp data', () => { 68 | // mock the flickr public feed api endpoint with invalid jsonp data that's missing parentheses 69 | jest.doMock('got', () => { 70 | return jest.fn(() => { 71 | const jsonpData = `jsonFlickrFeed{ 72 | "items": [ 73 | { 74 | "title": "Boating", 75 | "media": { 76 | "m": "http://farm4.staticflickr.com/3727/12608622365_9e9b8b377d_m.jpg" 77 | } 78 | } 79 | ] 80 | }`; 81 | return Promise.resolve({ 82 | body: jsonpData 83 | }); 84 | }); 85 | }); 86 | 87 | photoModel = require('../../app/photo_model'); 88 | 89 | return photoModel.getFlickrPhotos('california', 'all').catch(error => { 90 | expect(error.toString()).toMatch(/Failed to convert jsonp to json/); 91 | }); 92 | }); 93 | }); 94 | -------------------------------------------------------------------------------- /app/form_validator.js: -------------------------------------------------------------------------------- 1 | function isValidCommaDelimitedList(value) { 2 | // allow letters, commas, and spaces 3 | const commaDelimitedListRegEx = /^[A-Za-z,\s]+$/; 4 | return commaDelimitedListRegEx.test(value); 5 | } 6 | 7 | function isValidTagmode(value) { 8 | return value === 'all' || value === 'any'; 9 | } 10 | 11 | function hasValidFlickrAPIParams(tags, tagmode) { 12 | return isValidCommaDelimitedList(tags) && isValidTagmode(tagmode); 13 | } 14 | 15 | module.exports = { 16 | isValidCommaDelimitedList, 17 | isValidTagmode, 18 | hasValidFlickrAPIParams 19 | }; 20 | -------------------------------------------------------------------------------- /app/jsonp_helper.js: -------------------------------------------------------------------------------- 1 | function parseJSONP(jsonpData) { 2 | try { 3 | const startPos = jsonpData.indexOf('({'); 4 | const endPos = jsonpData.lastIndexOf('})'); 5 | let jsonString = jsonpData.substring(startPos + 1, endPos + 1); 6 | 7 | // remove escaped single quotes since they are not valid json 8 | jsonString = jsonString.replace(/\\'/g, "'"); 9 | 10 | return JSON.parse(jsonString); 11 | } catch (e) { 12 | const error = new Error(`Failed to convert jsonp to json. ${e.message}`); 13 | throw error; 14 | } 15 | } 16 | 17 | module.exports = { 18 | parseJSONP 19 | }; 20 | -------------------------------------------------------------------------------- /app/photo_model.js: -------------------------------------------------------------------------------- 1 | const got = require('got'); 2 | const querystring = require('querystring'); 3 | const jsonpHelper = require('./jsonp_helper'); 4 | 5 | function getFlickrPhotos(tags, tagmode) { 6 | const qs = querystring.stringify({ tags, tagmode, format: 'json' }); 7 | 8 | const options = { 9 | protocol: 'https:', 10 | hostname: 'api.flickr.com', 11 | path: `/services/feeds/photos_public.gne?${qs}`, 12 | timeout: 10000 13 | }; 14 | 15 | return got(options).then(response => { 16 | const photoFeed = jsonpHelper.parseJSONP(response.body); 17 | 18 | photoFeed.items.forEach(photo => { 19 | photo.media.t = photo.media.m.split('m.jpg')[0] + 't.jpg'; 20 | photo.media.b = photo.media.m.split('m.jpg')[0] + 'b.jpg'; 21 | }); 22 | 23 | return photoFeed.items; 24 | }); 25 | } 26 | 27 | module.exports = { 28 | getFlickrPhotos 29 | }; 30 | -------------------------------------------------------------------------------- /app/public/css/style.css: -------------------------------------------------------------------------------- 1 | .search-results ul { padding: 0; } 2 | .search-results li { display: inline; } 3 | 4 | .thumbnail { 5 | display: inline-block; 6 | margin: 0 10px 20px 0; 7 | } 8 | -------------------------------------------------------------------------------- /app/public/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gregjopa/express-app-testing-demo/c68df7b899b23f74d8dd8a0862fd4e512ec0f6f5/app/public/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /app/public/fonts/glyphicons-halflings-regular.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" standalone="no"?> 2 | <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" > 3 | <svg xmlns="http://www.w3.org/2000/svg"> 4 | <metadata></metadata> 5 | <defs> 6 | <font id="glyphicons_halflingsregular" horiz-adv-x="1200" > 7 | <font-face units-per-em="1200" ascent="960" descent="-240" /> 8 | <missing-glyph horiz-adv-x="500" /> 9 | <glyph /> 10 | <glyph /> 11 | <glyph unicode=" " /> 12 | <glyph unicode=" " /> 13 | <glyph unicode="*" d="M100 500v200h259l-183 183l141 141l183 -183v259h200v-259l183 183l141 -141l-183 -183h259v-200h-259l183 -183l-141 -141l-183 183v-259h-200v259l-183 -183l-141 141l183 183h-259z" /> 14 | <glyph unicode="+" d="M0 400v300h400v400h300v-400h400v-300h-400v-400h-300v400h-400z" /> 15 | <glyph unicode=" " /> 16 | <glyph unicode=" " horiz-adv-x="652" /> 17 | <glyph unicode=" " horiz-adv-x="1304" /> 18 | <glyph unicode=" " horiz-adv-x="652" /> 19 | <glyph unicode=" " horiz-adv-x="1304" /> 20 | <glyph unicode=" " horiz-adv-x="434" /> 21 | <glyph unicode=" " horiz-adv-x="326" /> 22 | <glyph unicode=" " horiz-adv-x="217" /> 23 | <glyph unicode=" " horiz-adv-x="217" /> 24 | <glyph unicode=" " horiz-adv-x="163" /> 25 | <glyph unicode=" " horiz-adv-x="260" /> 26 | <glyph unicode=" " horiz-adv-x="72" /> 27 | <glyph unicode=" " horiz-adv-x="260" /> 28 | <glyph unicode=" " horiz-adv-x="326" /> 29 | <glyph unicode="€" d="M100 500l100 100h113q0 47 5 100h-218l100 100h135q37 167 112 257q117 141 297 141q242 0 354 -189q60 -103 66 -209h-181q0 55 -25.5 99t-63.5 68t-75 36.5t-67 12.5q-24 0 -52.5 -10t-62.5 -32t-65.5 -67t-50.5 -107h379l-100 -100h-300q-6 -46 -6 -100h406l-100 -100 h-300q9 -74 33 -132t52.5 -91t62 -54.5t59 -29t46.5 -7.5q29 0 66 13t75 37t63.5 67.5t25.5 96.5h174q-31 -172 -128 -278q-107 -117 -274 -117q-205 0 -324 158q-36 46 -69 131.5t-45 205.5h-217z" /> 30 | <glyph unicode="−" d="M200 400h900v300h-900v-300z" /> 31 | <glyph unicode="◼" horiz-adv-x="500" d="M0 0z" /> 32 | <glyph unicode="☁" d="M-14 494q0 -80 56.5 -137t135.5 -57h750q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5z" /> 33 | <glyph unicode="✉" d="M0 100l400 400l200 -200l200 200l400 -400h-1200zM0 300v600l300 -300zM0 1100l600 -603l600 603h-1200zM900 600l300 300v-600z" /> 34 | <glyph unicode="✏" d="M-13 -13l333 112l-223 223zM187 403l214 -214l614 614l-214 214zM887 1103l214 -214l99 92q13 13 13 32.5t-13 33.5l-153 153q-15 13 -33 13t-33 -13z" /> 35 | <glyph unicode="" d="M0 1200h1200l-500 -550v-550h300v-100h-800v100h300v550z" /> 36 | <glyph unicode="" d="M14 84q18 -55 86 -75.5t147 5.5q65 21 109 69t44 90v606l600 155v-521q-64 16 -138 -7q-79 -26 -122.5 -83t-25.5 -111q18 -55 86 -75.5t147 4.5q70 23 111.5 63.5t41.5 95.5v881q0 10 -7 15.5t-17 2.5l-752 -193q-10 -3 -17 -12.5t-7 -19.5v-689q-64 17 -138 -7 q-79 -25 -122.5 -82t-25.5 -112z" /> 37 | <glyph unicode="" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233z" /> 38 | <glyph unicode="" d="M100 784q0 64 28 123t73 100.5t104.5 64t119 20.5t120 -38.5t104.5 -104.5q48 69 109.5 105t121.5 38t118.5 -20.5t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-149.5 152.5t-126.5 127.5 t-94 124.5t-33.5 117.5z" /> 39 | <glyph unicode="" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1z" /> 40 | <glyph unicode="" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1zM237 700l196 -142l-73 -226l192 140l195 -141l-74 229l193 140h-235l-77 211l-78 -211h-239z" /> 41 | <glyph unicode="" d="M0 0v143l400 257v100q-37 0 -68.5 74.5t-31.5 125.5v200q0 124 88 212t212 88t212 -88t88 -212v-200q0 -51 -31.5 -125.5t-68.5 -74.5v-100l400 -257v-143h-1200z" /> 42 | <glyph unicode="" d="M0 0v1100h1200v-1100h-1200zM100 100h100v100h-100v-100zM100 300h100v100h-100v-100zM100 500h100v100h-100v-100zM100 700h100v100h-100v-100zM100 900h100v100h-100v-100zM300 100h600v400h-600v-400zM300 600h600v400h-600v-400zM1000 100h100v100h-100v-100z M1000 300h100v100h-100v-100zM1000 500h100v100h-100v-100zM1000 700h100v100h-100v-100zM1000 900h100v100h-100v-100z" /> 43 | <glyph unicode="" d="M0 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM0 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5zM600 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM600 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5z" /> 44 | <glyph unicode="" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 450v200q0 21 14.5 35.5t35.5 14.5h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5z" /> 45 | <glyph unicode="" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v200q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5 t-14.5 -35.5v-200zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5z" /> 46 | <glyph unicode="" d="M29 454l419 -420l818 820l-212 212l-607 -607l-206 207z" /> 47 | <glyph unicode="" d="M106 318l282 282l-282 282l212 212l282 -282l282 282l212 -212l-282 -282l282 -282l-212 -212l-282 282l-282 -282z" /> 48 | <glyph unicode="" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233zM300 600v200h100v100h200v-100h100v-200h-100v-100h-200v100h-100z" /> 49 | <glyph unicode="" d="M23 694q0 200 142 342t342 142t342 -142t142 -342q0 -141 -78 -262l300 -299q7 -7 7 -18t-7 -18l-109 -109q-8 -8 -18 -8t-18 8l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 694q0 -136 97 -233t234 -97t233.5 97t96.5 233t-96.5 233t-233.5 97t-234 -97 t-97 -233zM300 601h400v200h-400v-200z" /> 50 | <glyph unicode="" d="M23 600q0 183 105 331t272 210v-166q-103 -55 -165 -155t-62 -220q0 -177 125 -302t302 -125t302 125t125 302q0 120 -62 220t-165 155v166q167 -62 272 -210t105 -331q0 -118 -45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5 zM500 750q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v400q0 21 -14.5 35.5t-35.5 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-400z" /> 51 | <glyph unicode="" d="M100 1h200v300h-200v-300zM400 1v500h200v-500h-200zM700 1v800h200v-800h-200zM1000 1v1200h200v-1200h-200z" /> 52 | <glyph unicode="" d="M26 601q0 -33 6 -74l151 -38l2 -6q14 -49 38 -93l3 -5l-80 -134q45 -59 105 -105l133 81l5 -3q45 -26 94 -39l5 -2l38 -151q40 -5 74 -5q27 0 74 5l38 151l6 2q46 13 93 39l5 3l134 -81q56 44 104 105l-80 134l3 5q24 44 39 93l1 6l152 38q5 40 5 74q0 28 -5 73l-152 38 l-1 6q-16 51 -39 93l-3 5l80 134q-44 58 -104 105l-134 -81l-5 3q-45 25 -93 39l-6 1l-38 152q-40 5 -74 5q-27 0 -74 -5l-38 -152l-5 -1q-50 -14 -94 -39l-5 -3l-133 81q-59 -47 -105 -105l80 -134l-3 -5q-25 -47 -38 -93l-2 -6l-151 -38q-6 -48 -6 -73zM385 601 q0 88 63 151t152 63t152 -63t63 -151q0 -89 -63 -152t-152 -63t-152 63t-63 152z" /> 53 | <glyph unicode="" d="M100 1025v50q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-50q0 -11 -7 -18t-18 -7h-1050q-11 0 -18 7t-7 18zM200 100v800h900v-800q0 -41 -29.5 -71t-70.5 -30h-700q-41 0 -70.5 30 t-29.5 71zM300 100h100v700h-100v-700zM500 100h100v700h-100v-700zM500 1100h300v100h-300v-100zM700 100h100v700h-100v-700zM900 100h100v700h-100v-700z" /> 54 | <glyph unicode="" d="M1 601l656 644l644 -644h-200v-600h-300v400h-300v-400h-300v600h-200z" /> 55 | <glyph unicode="" d="M100 25v1150q0 11 7 18t18 7h475v-500h400v-675q0 -11 -7 -18t-18 -7h-850q-11 0 -18 7t-7 18zM700 800v300l300 -300h-300z" /> 56 | <glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 500v400h100 v-300h200v-100h-300z" /> 57 | <glyph unicode="" d="M-100 0l431 1200h209l-21 -300h162l-20 300h208l431 -1200h-538l-41 400h-242l-40 -400h-539zM488 500h224l-27 300h-170z" /> 58 | <glyph unicode="" d="M0 0v400h490l-290 300h200v500h300v-500h200l-290 -300h490v-400h-1100zM813 200h175v100h-175v-100z" /> 59 | <glyph unicode="" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM188 600q0 -170 121 -291t291 -121t291 121t121 291t-121 291t-291 121 t-291 -121t-121 -291zM350 600h150v300h200v-300h150l-250 -300z" /> 60 | <glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM350 600l250 300 l250 -300h-150v-300h-200v300h-150z" /> 61 | <glyph unicode="" d="M0 25v475l200 700h800l199 -700l1 -475q0 -11 -7 -18t-18 -7h-1150q-11 0 -18 7t-7 18zM200 500h200l50 -200h300l50 200h200l-97 500h-606z" /> 62 | <glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 397v401 l297 -200z" /> 63 | <glyph unicode="" d="M23 600q0 -118 45.5 -224.5t123 -184t184 -123t224.5 -45.5t224.5 45.5t184 123t123 184t45.5 224.5h-150q0 -177 -125 -302t-302 -125t-302 125t-125 302t125 302t302 125q136 0 246 -81l-146 -146h400v400l-145 -145q-157 122 -355 122q-118 0 -224.5 -45.5t-184 -123 t-123 -184t-45.5 -224.5z" /> 64 | <glyph unicode="" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5q198 0 355 -122l145 145v-400h-400l147 147q-112 80 -247 80q-177 0 -302 -125t-125 -302h-150zM100 0v400h400l-147 -147q112 -80 247 -80q177 0 302 125t125 302h150q0 -118 -45.5 -224.5t-123 -184t-184 -123 t-224.5 -45.5q-198 0 -355 122z" /> 65 | <glyph unicode="" d="M100 0h1100v1200h-1100v-1200zM200 100v900h900v-900h-900zM300 200v100h100v-100h-100zM300 400v100h100v-100h-100zM300 600v100h100v-100h-100zM300 800v100h100v-100h-100zM500 200h500v100h-500v-100zM500 400v100h500v-100h-500zM500 600v100h500v-100h-500z M500 800v100h500v-100h-500z" /> 66 | <glyph unicode="" d="M0 100v600q0 41 29.5 70.5t70.5 29.5h100v200q0 82 59 141t141 59h300q82 0 141 -59t59 -141v-200h100q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-900q-41 0 -70.5 29.5t-29.5 70.5zM400 800h300v150q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-150z" /> 67 | <glyph unicode="" d="M100 0v1100h100v-1100h-100zM300 400q60 60 127.5 84t127.5 17.5t122 -23t119 -30t110 -11t103 42t91 120.5v500q-40 -81 -101.5 -115.5t-127.5 -29.5t-138 25t-139.5 40t-125.5 25t-103 -29.5t-65 -115.5v-500z" /> 68 | <glyph unicode="" d="M0 275q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 127 70.5 231.5t184.5 161.5t245 57t245 -57t184.5 -161.5t70.5 -231.5v-300q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 116 -49.5 227t-131 192.5t-192.5 131t-227 49.5t-227 -49.5t-192.5 -131t-131 -192.5 t-49.5 -227v-300zM200 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14zM800 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14z" /> 69 | <glyph unicode="" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM688 459l141 141l-141 141l71 71l141 -141l141 141l71 -71l-141 -141l141 -141l-71 -71l-141 141l-141 -141z" /> 70 | <glyph unicode="" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM700 857l69 53q111 -135 111 -310q0 -169 -106 -302l-67 54q86 110 86 248q0 146 -93 257z" /> 71 | <glyph unicode="" d="M0 401v400h300l300 200v-800l-300 200h-300zM702 858l69 53q111 -135 111 -310q0 -170 -106 -303l-67 55q86 110 86 248q0 145 -93 257zM889 951l7 -8q123 -151 123 -344q0 -189 -119 -339l-7 -8l81 -66l6 8q142 178 142 405q0 230 -144 408l-6 8z" /> 72 | <glyph unicode="" d="M0 0h500v500h-200v100h-100v-100h-200v-500zM0 600h100v100h400v100h100v100h-100v300h-500v-600zM100 100v300h300v-300h-300zM100 800v300h300v-300h-300zM200 200v100h100v-100h-100zM200 900h100v100h-100v-100zM500 500v100h300v-300h200v-100h-100v-100h-200v100 h-100v100h100v200h-200zM600 0v100h100v-100h-100zM600 1000h100v-300h200v-300h300v200h-200v100h200v500h-600v-200zM800 800v300h300v-300h-300zM900 0v100h300v-100h-300zM900 900v100h100v-100h-100zM1100 200v100h100v-100h-100z" /> 73 | <glyph unicode="" d="M0 200h100v1000h-100v-1000zM100 0v100h300v-100h-300zM200 200v1000h100v-1000h-100zM500 0v91h100v-91h-100zM500 200v1000h200v-1000h-200zM700 0v91h100v-91h-100zM800 200v1000h100v-1000h-100zM900 0v91h200v-91h-200zM1000 200v1000h200v-1000h-200z" /> 74 | <glyph unicode="" d="M0 700l1 475q0 10 7.5 17.5t17.5 7.5h474l700 -700l-500 -500zM148 953q0 -42 29 -71q30 -30 71.5 -30t71.5 30q29 29 29 71t-29 71q-30 30 -71.5 30t-71.5 -30q-29 -29 -29 -71z" /> 75 | <glyph unicode="" d="M1 700l1 475q0 11 7 18t18 7h474l700 -700l-500 -500zM148 953q0 -42 30 -71q29 -30 71 -30t71 30q30 29 30 71t-30 71q-29 30 -71 30t-71 -30q-30 -29 -30 -71zM701 1200h100l700 -700l-500 -500l-50 50l450 450z" /> 76 | <glyph unicode="" d="M100 0v1025l175 175h925v-1000l-100 -100v1000h-750l-100 -100h750v-1000h-900z" /> 77 | <glyph unicode="" d="M200 0l450 444l450 -443v1150q0 20 -14.5 35t-35.5 15h-800q-21 0 -35.5 -15t-14.5 -35v-1151z" /> 78 | <glyph unicode="" d="M0 100v700h200l100 -200h600l100 200h200v-700h-200v200h-800v-200h-200zM253 829l40 -124h592l62 124l-94 346q-2 11 -10 18t-18 7h-450q-10 0 -18 -7t-10 -18zM281 24l38 152q2 10 11.5 17t19.5 7h500q10 0 19.5 -7t11.5 -17l38 -152q2 -10 -3.5 -17t-15.5 -7h-600 q-10 0 -15.5 7t-3.5 17z" /> 79 | <glyph unicode="" d="M0 200q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-150q-4 8 -11.5 21.5t-33 48t-53 61t-69 48t-83.5 21.5h-200q-41 0 -82 -20.5t-70 -50t-52 -59t-34 -50.5l-12 -20h-150q-41 0 -70.5 -29.5t-29.5 -70.5v-600z M356 500q0 100 72 172t172 72t172 -72t72 -172t-72 -172t-172 -72t-172 72t-72 172zM494 500q0 -44 31 -75t75 -31t75 31t31 75t-31 75t-75 31t-75 -31t-31 -75zM900 700v100h100v-100h-100z" /> 80 | <glyph unicode="" d="M53 0h365v66q-41 0 -72 11t-49 38t1 71l92 234h391l82 -222q16 -45 -5.5 -88.5t-74.5 -43.5v-66h417v66q-34 1 -74 43q-18 19 -33 42t-21 37l-6 13l-385 998h-93l-399 -1006q-24 -48 -52 -75q-12 -12 -33 -25t-36 -20l-15 -7v-66zM416 521l178 457l46 -140l116 -317h-340 z" /> 81 | <glyph unicode="" d="M100 0v89q41 7 70.5 32.5t29.5 65.5v827q0 28 -1 39.5t-5.5 26t-15.5 21t-29 14t-49 14.5v71l471 -1q120 0 213 -88t93 -228q0 -55 -11.5 -101.5t-28 -74t-33.5 -47.5t-28 -28l-12 -7q8 -3 21.5 -9t48 -31.5t60.5 -58t47.5 -91.5t21.5 -129q0 -84 -59 -156.5t-142 -111 t-162 -38.5h-500zM400 200h161q89 0 153 48.5t64 132.5q0 90 -62.5 154.5t-156.5 64.5h-159v-400zM400 700h139q76 0 130 61.5t54 138.5q0 82 -84 130.5t-239 48.5v-379z" /> 82 | <glyph unicode="" d="M200 0v57q77 7 134.5 40.5t65.5 80.5l173 849q10 56 -10 74t-91 37q-6 1 -10.5 2.5t-9.5 2.5v57h425l2 -57q-33 -8 -62 -25.5t-46 -37t-29.5 -38t-17.5 -30.5l-5 -12l-128 -825q-10 -52 14 -82t95 -36v-57h-500z" /> 83 | <glyph unicode="" d="M-75 200h75v800h-75l125 167l125 -167h-75v-800h75l-125 -167zM300 900v300h150h700h150v-300h-50q0 29 -8 48.5t-18.5 30t-33.5 15t-39.5 5.5t-50.5 1h-200v-850l100 -50v-100h-400v100l100 50v850h-200q-34 0 -50.5 -1t-40 -5.5t-33.5 -15t-18.5 -30t-8.5 -48.5h-49z " /> 84 | <glyph unicode="" d="M33 51l167 125v-75h800v75l167 -125l-167 -125v75h-800v-75zM100 901v300h150h700h150v-300h-50q0 29 -8 48.5t-18 30t-33.5 15t-40 5.5t-50.5 1h-200v-650l100 -50v-100h-400v100l100 50v650h-200q-34 0 -50.5 -1t-39.5 -5.5t-33.5 -15t-18.5 -30t-8 -48.5h-50z" /> 85 | <glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 350q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM0 650q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1000q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 950q0 -20 14.5 -35t35.5 -15h600q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-600q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" /> 86 | <glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 650q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM200 350q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM200 950q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" /> 87 | <glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1000q-21 0 -35.5 15 t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-600 q-21 0 -35.5 15t-14.5 35z" /> 88 | <glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100 q-21 0 -35.5 15t-14.5 35z" /> 89 | <glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM300 50v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800 q-21 0 -35.5 15t-14.5 35zM300 650v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 950v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15 h-800q-21 0 -35.5 15t-14.5 35z" /> 90 | <glyph unicode="" d="M-101 500v100h201v75l166 -125l-166 -125v75h-201zM300 0h100v1100h-100v-1100zM500 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35 v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 650q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100 q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100z" /> 91 | <glyph unicode="" d="M1 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 650 q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM801 0v1100h100v-1100 h-100zM934 550l167 -125v75h200v100h-200v75z" /> 92 | <glyph unicode="" d="M0 275v650q0 31 22 53t53 22h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53zM900 600l300 300v-600z" /> 93 | <glyph unicode="" d="M0 44v1012q0 18 13 31t31 13h1112q19 0 31.5 -13t12.5 -31v-1012q0 -18 -12.5 -31t-31.5 -13h-1112q-18 0 -31 13t-13 31zM100 263l247 182l298 -131l-74 156l293 318l236 -288v500h-1000v-737zM208 750q0 56 39 95t95 39t95 -39t39 -95t-39 -95t-95 -39t-95 39t-39 95z " /> 94 | <glyph unicode="" d="M148 745q0 124 60.5 231.5t165 172t226.5 64.5q123 0 227 -63t164.5 -169.5t60.5 -229.5t-73 -272q-73 -114 -166.5 -237t-150.5 -189l-57 -66q-10 9 -27 26t-66.5 70.5t-96 109t-104 135.5t-100.5 155q-63 139 -63 262zM342 772q0 -107 75.5 -182.5t181.5 -75.5 q107 0 182.5 75.5t75.5 182.5t-75.5 182t-182.5 75t-182 -75.5t-75 -181.5z" /> 95 | <glyph unicode="" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM173 600q0 -177 125.5 -302t301.5 -125v854q-176 0 -301.5 -125 t-125.5 -302z" /> 96 | <glyph unicode="" d="M117 406q0 94 34 186t88.5 172.5t112 159t115 177t87.5 194.5q21 -71 57.5 -142.5t76 -130.5t83 -118.5t82 -117t70 -116t50 -125.5t18.5 -136q0 -89 -39 -165.5t-102 -126.5t-140 -79.5t-156 -33.5q-114 6 -211.5 53t-161.5 139t-64 210zM243 414q14 -82 59.5 -136 t136.5 -80l16 98q-7 6 -18 17t-34 48t-33 77q-15 73 -14 143.5t10 122.5l9 51q-92 -110 -119.5 -185t-12.5 -156z" /> 97 | <glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5q366 -6 397 -14l-186 -186h-311q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v125l200 200v-225q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM436 341l161 50l412 412l-114 113l-405 -405zM995 1015l113 -113l113 113l-21 85l-92 28z" /> 98 | <glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h261l2 -80q-133 -32 -218 -120h-145q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-53q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5 zM423 524q30 38 81.5 64t103 35.5t99 14t77.5 3.5l29 -1v-209l360 324l-359 318v-216q-7 0 -19 -1t-48 -8t-69.5 -18.5t-76.5 -37t-76.5 -59t-62 -88t-39.5 -121.5z" /> 99 | <glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q61 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-169q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM342 632l283 -284l567 567l-137 137l-430 -431l-146 147z" /> 100 | <glyph unicode="" d="M0 603l300 296v-198h200v200h-200l300 300l295 -300h-195v-200h200v198l300 -296l-300 -300v198h-200v-200h195l-295 -300l-300 300h200v200h-200v-198z" /> 101 | <glyph unicode="" d="M200 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-1100l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" /> 102 | <glyph unicode="" d="M0 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-487l500 487v-1100l-500 488v-488l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" /> 103 | <glyph unicode="" d="M136 550l564 550v-487l500 487v-1100l-500 488v-488z" /> 104 | <glyph unicode="" d="M200 0l900 550l-900 550v-1100z" /> 105 | <glyph unicode="" d="M200 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5t-14.5 -35.5v-800zM600 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" /> 106 | <glyph unicode="" d="M200 150q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v800q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" /> 107 | <glyph unicode="" d="M0 0v1100l500 -487v487l564 -550l-564 -550v488z" /> 108 | <glyph unicode="" d="M0 0v1100l500 -487v487l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-500 -488v488z" /> 109 | <glyph unicode="" d="M300 0v1100l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438z" /> 110 | <glyph unicode="" d="M100 250v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5zM100 500h1100l-550 564z" /> 111 | <glyph unicode="" d="M185 599l592 -592l240 240l-353 353l353 353l-240 240z" /> 112 | <glyph unicode="" d="M272 194l353 353l-353 353l241 240l572 -571l21 -22l-1 -1v-1l-592 -591z" /> 113 | <glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h200v-200h200v200h200v200h-200v200h-200v-200h-200v-200z" /> 114 | <glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h600v200h-600v-200z" /> 115 | <glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM246 459l213 -213l141 142l141 -142l213 213l-142 141l142 141l-213 212l-141 -141l-141 142l-212 -213l141 -141 z" /> 116 | <glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM270 551l276 -277l411 411l-175 174l-236 -236l-102 102z" /> 117 | <glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM364 700h143q4 0 11.5 -1t11 -1t6.5 3t3 9t1 11t3.5 8.5t3.5 6t5.5 4t6.5 2.5t9 1.5t9 0.5h11.5h12.5 q19 0 30 -10t11 -26q0 -22 -4 -28t-27 -22q-5 -1 -12.5 -3t-27 -13.5t-34 -27t-26.5 -46t-11 -68.5h200q5 3 14 8t31.5 25.5t39.5 45.5t31 69t14 94q0 51 -17.5 89t-42 58t-58.5 32t-58.5 15t-51.5 3q-50 0 -90.5 -12t-75 -38.5t-53.5 -74.5t-19 -114zM500 300h200v100h-200 v-100z" /> 118 | <glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM400 300h400v100h-100v300h-300v-100h100v-200h-100v-100zM500 800h200v100h-200v-100z" /> 119 | <glyph unicode="" d="M0 500v200h195q31 125 98.5 199.5t206.5 100.5v200h200v-200q54 -20 113 -60t112.5 -105.5t71.5 -134.5h203v-200h-203q-25 -102 -116.5 -186t-180.5 -117v-197h-200v197q-140 27 -208 102.5t-98 200.5h-194zM290 500q24 -73 79.5 -127.5t130.5 -78.5v206h200v-206 q149 48 201 206h-201v200h200q-25 74 -75.5 127t-124.5 77v-204h-200v203q-75 -23 -130 -77t-79 -126h209v-200h-210z" /> 120 | <glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM356 465l135 135 l-135 135l109 109l135 -135l135 135l109 -109l-135 -135l135 -135l-109 -109l-135 135l-135 -135z" /> 121 | <glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM322 537l141 141 l87 -87l204 205l142 -142l-346 -345z" /> 122 | <glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -115 62 -215l568 567q-100 62 -216 62q-171 0 -292.5 -121.5t-121.5 -292.5zM391 245q97 -59 209 -59q171 0 292.5 121.5t121.5 292.5 q0 112 -59 209z" /> 123 | <glyph unicode="" d="M0 547l600 453v-300h600v-300h-600v-301z" /> 124 | <glyph unicode="" d="M0 400v300h600v300l600 -453l-600 -448v301h-600z" /> 125 | <glyph unicode="" d="M204 600l450 600l444 -600h-298v-600h-300v600h-296z" /> 126 | <glyph unicode="" d="M104 600h296v600h300v-600h298l-449 -600z" /> 127 | <glyph unicode="" d="M0 200q6 132 41 238.5t103.5 193t184 138t271.5 59.5v271l600 -453l-600 -448v301q-95 -2 -183 -20t-170 -52t-147 -92.5t-100 -135.5z" /> 128 | <glyph unicode="" d="M0 0v400l129 -129l294 294l142 -142l-294 -294l129 -129h-400zM635 777l142 -142l294 294l129 -129v400h-400l129 -129z" /> 129 | <glyph unicode="" d="M34 176l295 295l-129 129h400v-400l-129 130l-295 -295zM600 600v400l129 -129l295 295l142 -141l-295 -295l129 -130h-400z" /> 130 | <glyph unicode="" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5t224.5 -45.5t184 -123t123 -184t45.5 -224.5t-45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5zM456 851l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5 t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5h-207q-21 0 -33 -14.5t-8 -34.5zM500 300h200v100h-200v-100z" /> 131 | <glyph unicode="" d="M0 800h100v-200h400v300h200v-300h400v200h100v100h-111q1 1 1 6.5t-1.5 15t-3.5 17.5l-34 172q-11 39 -41.5 63t-69.5 24q-32 0 -61 -17l-239 -144q-22 -13 -40 -35q-19 24 -40 36l-238 144q-33 18 -62 18q-39 0 -69.5 -23t-40.5 -61l-35 -177q-2 -8 -3 -18t-1 -15v-6 h-111v-100zM100 0h400v400h-400v-400zM200 900q-3 0 14 48t36 96l18 47l213 -191h-281zM700 0v400h400v-400h-400zM731 900l202 197q5 -12 12 -32.5t23 -64t25 -72t7 -28.5h-269z" /> 132 | <glyph unicode="" d="M0 -22v143l216 193q-9 53 -13 83t-5.5 94t9 113t38.5 114t74 124q47 60 99.5 102.5t103 68t127.5 48t145.5 37.5t184.5 43.5t220 58.5q0 -189 -22 -343t-59 -258t-89 -181.5t-108.5 -120t-122 -68t-125.5 -30t-121.5 -1.5t-107.5 12.5t-87.5 17t-56.5 7.5l-99 -55z M238.5 300.5q19.5 -6.5 86.5 76.5q55 66 367 234q70 38 118.5 69.5t102 79t99 111.5t86.5 148q22 50 24 60t-6 19q-7 5 -17 5t-26.5 -14.5t-33.5 -39.5q-35 -51 -113.5 -108.5t-139.5 -89.5l-61 -32q-369 -197 -458 -401q-48 -111 -28.5 -117.5z" /> 133 | <glyph unicode="" d="M111 408q0 -33 5 -63q9 -56 44 -119.5t105 -108.5q31 -21 64 -16t62 23.5t57 49.5t48 61.5t35 60.5q32 66 39 184.5t-13 157.5q79 -80 122 -164t26 -184q-5 -33 -20.5 -69.5t-37.5 -80.5q-10 -19 -14.5 -29t-12 -26t-9 -23.5t-3 -19t2.5 -15.5t11 -9.5t19.5 -5t30.5 2.5 t42 8q57 20 91 34t87.5 44.5t87 64t65.5 88.5t47 122q38 172 -44.5 341.5t-246.5 278.5q22 -44 43 -129q39 -159 -32 -154q-15 2 -33 9q-79 33 -120.5 100t-44 175.5t48.5 257.5q-13 -8 -34 -23.5t-72.5 -66.5t-88.5 -105.5t-60 -138t-8 -166.5q2 -12 8 -41.5t8 -43t6 -39.5 t3.5 -39.5t-1 -33.5t-6 -31.5t-13.5 -24t-21 -20.5t-31 -12q-38 -10 -67 13t-40.5 61.5t-15 81.5t10.5 75q-52 -46 -83.5 -101t-39 -107t-7.5 -85z" /> 134 | <glyph unicode="" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5t145.5 -23.5t132.5 -59t116.5 -83.5t97 -90t74.5 -85.5t49 -63.5t20 -30l26 -40l-26 -40q-6 -10 -20 -30t-49 -63.5t-74.5 -85.5t-97 -90t-116.5 -83.5t-132.5 -59t-145.5 -23.5 t-145.5 23.5t-132.5 59t-116.5 83.5t-97 90t-74.5 85.5t-49 63.5t-20 30zM120 600q7 -10 40.5 -58t56 -78.5t68 -77.5t87.5 -75t103 -49.5t125 -21.5t123.5 20t100.5 45.5t85.5 71.5t66.5 75.5t58 81.5t47 66q-1 1 -28.5 37.5t-42 55t-43.5 53t-57.5 63.5t-58.5 54 q49 -74 49 -163q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l105 105q-37 24 -75 72t-57 84l-20 36z" /> 135 | <glyph unicode="" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5q61 0 121 -17l37 142h148l-314 -1200h-148l37 143q-82 21 -165 71.5t-140 102t-109.5 112t-72 88.5t-29.5 43zM120 600q210 -282 393 -336l37 141q-107 18 -178.5 101.5t-71.5 193.5 q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l47 47l23 87q-30 28 -59 69t-44 68l-14 26zM780 161l38 145q22 15 44.5 34t46 44t40.5 44t41 50.5t33.5 43.5t33 44t24.5 34q-97 127 -140 175l39 146q67 -54 131.5 -125.5t87.5 -103.5t36 -52l26 -40l-26 -40 q-7 -12 -25.5 -38t-63.5 -79.5t-95.5 -102.5t-124 -100t-146.5 -79z" /> 136 | <glyph unicode="" d="M-97.5 34q13.5 -34 50.5 -34h1294q37 0 50.5 35.5t-7.5 67.5l-642 1056q-20 34 -48 36.5t-48 -29.5l-642 -1066q-21 -32 -7.5 -66zM155 200l445 723l445 -723h-345v100h-200v-100h-345zM500 600l100 -300l100 300v100h-200v-100z" /> 137 | <glyph unicode="" d="M100 262v41q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44t106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -91 100 -113v-64q0 -20 -13 -28.5t-32 0.5l-94 78h-222l-94 -78q-19 -9 -32 -0.5t-13 28.5 v64q0 22 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5z" /> 138 | <glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v750h-1100v-750zM0 900h1100v150q0 21 -14.5 35.5t-35.5 14.5h-150v100h-100v-100h-500v100h-100v-100h-150q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 100v100h100v-100h-100zM100 300v100h100v-100h-100z M100 500v100h100v-100h-100zM300 100v100h100v-100h-100zM300 300v100h100v-100h-100zM300 500v100h100v-100h-100zM500 100v100h100v-100h-100zM500 300v100h100v-100h-100zM500 500v100h100v-100h-100zM700 100v100h100v-100h-100zM700 300v100h100v-100h-100zM700 500 v100h100v-100h-100zM900 100v100h100v-100h-100zM900 300v100h100v-100h-100zM900 500v100h100v-100h-100z" /> 139 | <glyph unicode="" d="M0 200v200h259l600 600h241v198l300 -295l-300 -300v197h-159l-600 -600h-341zM0 800h259l122 -122l141 142l-181 180h-341v-200zM678 381l141 142l122 -123h159v198l300 -295l-300 -300v197h-241z" /> 140 | <glyph unicode="" d="M0 400v600q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5z" /> 141 | <glyph unicode="" d="M100 600v200h300v-250q0 -113 6 -145q17 -92 102 -117q39 -11 92 -11q37 0 66.5 5.5t50 15.5t36 24t24 31.5t14 37.5t7 42t2.5 45t0 47v25v250h300v-200q0 -42 -3 -83t-15 -104t-31.5 -116t-58 -109.5t-89 -96.5t-129 -65.5t-174.5 -25.5t-174.5 25.5t-129 65.5t-89 96.5 t-58 109.5t-31.5 116t-15 104t-3 83zM100 900v300h300v-300h-300zM800 900v300h300v-300h-300z" /> 142 | <glyph unicode="" d="M-30 411l227 -227l352 353l353 -353l226 227l-578 579z" /> 143 | <glyph unicode="" d="M70 797l580 -579l578 579l-226 227l-353 -353l-352 353z" /> 144 | <glyph unicode="" d="M-198 700l299 283l300 -283h-203v-400h385l215 -200h-800v600h-196zM402 1000l215 -200h381v-400h-198l299 -283l299 283h-200v600h-796z" /> 145 | <glyph unicode="" d="M18 939q-5 24 10 42q14 19 39 19h896l38 162q5 17 18.5 27.5t30.5 10.5h94q20 0 35 -14.5t15 -35.5t-15 -35.5t-35 -14.5h-54l-201 -961q-2 -4 -6 -10.5t-19 -17.5t-33 -11h-31v-50q0 -20 -14.5 -35t-35.5 -15t-35.5 15t-14.5 35v50h-300v-50q0 -20 -14.5 -35t-35.5 -15 t-35.5 15t-14.5 35v50h-50q-21 0 -35.5 15t-14.5 35q0 21 14.5 35.5t35.5 14.5h535l48 200h-633q-32 0 -54.5 21t-27.5 43z" /> 146 | <glyph unicode="" d="M0 0v800h1200v-800h-1200zM0 900v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-100h-1200z" /> 147 | <glyph unicode="" d="M1 0l300 700h1200l-300 -700h-1200zM1 400v600h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-200h-1000z" /> 148 | <glyph unicode="" d="M302 300h198v600h-198l298 300l298 -300h-198v-600h198l-298 -300z" /> 149 | <glyph unicode="" d="M0 600l300 298v-198h600v198l300 -298l-300 -297v197h-600v-197z" /> 150 | <glyph unicode="" d="M0 100v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM31 400l172 739q5 22 23 41.5t38 19.5h672q19 0 37.5 -22.5t23.5 -45.5l172 -732h-1138zM800 100h100v100h-100v-100z M1000 100h100v100h-100v-100z" /> 151 | <glyph unicode="" d="M-101 600v50q0 24 25 49t50 38l25 13v-250l-11 5.5t-24 14t-30 21.5t-24 27.5t-11 31.5zM100 500v250v8v8v7t0.5 7t1.5 5.5t2 5t3 4t4.5 3.5t6 1.5t7.5 0.5h200l675 250v-850l-675 200h-38l47 -276q2 -12 -3 -17.5t-11 -6t-21 -0.5h-8h-83q-20 0 -34.5 14t-18.5 35 q-55 337 -55 351zM1100 200v850q0 21 14.5 35.5t35.5 14.5q20 0 35 -14.5t15 -35.5v-850q0 -20 -15 -35t-35 -15q-21 0 -35.5 15t-14.5 35z" /> 152 | <glyph unicode="" d="M74 350q0 21 13.5 35.5t33.5 14.5h18l117 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3 32t29 13h94q20 0 29 -10.5t3 -29.5q-18 -36 -18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q20 0 33.5 -14.5t13.5 -35.5q0 -20 -13 -40t-31 -27q-8 -3 -23 -8.5 t-65 -20t-103 -25t-132.5 -19.5t-158.5 -9q-125 0 -245.5 20.5t-178.5 40.5l-58 20q-18 7 -31 27.5t-13 40.5zM497 110q12 -49 40 -79.5t63 -30.5t63 30.5t39 79.5q-48 -6 -102 -6t-103 6z" /> 153 | <glyph unicode="" d="M21 445l233 -45l-78 -224l224 78l45 -233l155 179l155 -179l45 233l224 -78l-78 224l234 45l-180 155l180 156l-234 44l78 225l-224 -78l-45 233l-155 -180l-155 180l-45 -233l-224 78l78 -225l-233 -44l179 -156z" /> 154 | <glyph unicode="" d="M0 200h200v600h-200v-600zM300 275q0 -75 100 -75h61q124 -100 139 -100h250q46 0 83 57l238 344q29 31 29 74v100q0 44 -30.5 84.5t-69.5 40.5h-328q28 118 28 125v150q0 44 -30.5 84.5t-69.5 40.5h-50q-27 0 -51 -20t-38 -48l-96 -198l-145 -196q-20 -26 -20 -63v-400z M400 300v375l150 213l100 212h50v-175l-50 -225h450v-125l-250 -375h-214l-136 100h-100z" /> 155 | <glyph unicode="" d="M0 400v600h200v-600h-200zM300 525v400q0 75 100 75h61q124 100 139 100h250q46 0 83 -57l238 -344q29 -31 29 -74v-100q0 -44 -30.5 -84.5t-69.5 -40.5h-328q28 -118 28 -125v-150q0 -44 -30.5 -84.5t-69.5 -40.5h-50q-27 0 -51 20t-38 48l-96 198l-145 196 q-20 26 -20 63zM400 525l150 -212l100 -213h50v175l-50 225h450v125l-250 375h-214l-136 -100h-100v-375z" /> 156 | <glyph unicode="" d="M8 200v600h200v-600h-200zM308 275v525q0 17 14 35.5t28 28.5l14 9l362 230q14 6 25 6q17 0 29 -12l109 -112q14 -14 14 -34q0 -18 -11 -32l-85 -121h302q85 0 138.5 -38t53.5 -110t-54.5 -111t-138.5 -39h-107l-130 -339q-7 -22 -20.5 -41.5t-28.5 -19.5h-341 q-7 0 -90 81t-83 94zM408 289l100 -89h293l131 339q6 21 19.5 41t28.5 20h203q16 0 25 15t9 36q0 20 -9 34.5t-25 14.5h-457h-6.5h-7.5t-6.5 0.5t-6 1t-5 1.5t-5.5 2.5t-4 4t-4 5.5q-5 12 -5 20q0 14 10 27l147 183l-86 83l-339 -236v-503z" /> 157 | <glyph unicode="" d="M-101 651q0 72 54 110t139 38l302 -1l-85 121q-11 16 -11 32q0 21 14 34l109 113q13 12 29 12q11 0 25 -6l365 -230q7 -4 17 -10.5t26.5 -26t16.5 -36.5v-526q0 -13 -86 -93.5t-94 -80.5h-341q-16 0 -29.5 20t-19.5 41l-130 339h-107q-84 0 -139 39t-55 111zM-1 601h222 q15 0 28.5 -20.5t19.5 -40.5l131 -339h293l107 89v502l-343 237l-87 -83l145 -184q10 -11 10 -26q0 -11 -5 -20q-1 -3 -3.5 -5.5l-4 -4t-5 -2.5t-5.5 -1.5t-6.5 -1t-6.5 -0.5h-7.5h-6.5h-476v-100zM1000 201v600h200v-600h-200z" /> 158 | <glyph unicode="" d="M97 719l230 -363q4 -6 10.5 -15.5t26 -25t36.5 -15.5h525q13 0 94 83t81 90v342q0 15 -20 28.5t-41 19.5l-339 131v106q0 84 -39 139t-111 55t-110 -53.5t-38 -138.5v-302l-121 84q-15 12 -33.5 11.5t-32.5 -13.5l-112 -110q-22 -22 -6 -53zM172 739l83 86l183 -146 q22 -18 47 -5q3 1 5.5 3.5l4 4t2.5 5t1.5 5.5t1 6.5t0.5 6.5v7.5v6.5v456q0 22 25 31t50 -0.5t25 -30.5v-202q0 -16 20 -29.5t41 -19.5l339 -130v-294l-89 -100h-503zM400 0v200h600v-200h-600z" /> 159 | <glyph unicode="" d="M2 585q-16 -31 6 -53l112 -110q13 -13 32 -13.5t34 10.5l121 85q0 -51 -0.5 -153.5t-0.5 -148.5q0 -84 38.5 -138t110.5 -54t111 55t39 139v106l339 131q20 6 40.5 19.5t20.5 28.5v342q0 7 -81 90t-94 83h-525q-17 0 -35.5 -14t-28.5 -28l-10 -15zM77 565l236 339h503 l89 -100v-294l-340 -130q-20 -6 -40 -20t-20 -29v-202q0 -22 -25 -31t-50 0t-25 31v456v14.5t-1.5 11.5t-5 12t-9.5 7q-24 13 -46 -5l-184 -146zM305 1104v200h600v-200h-600z" /> 160 | <glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM298 701l2 -201h300l-2 -194l402 294l-402 298v-197h-300z" /> 161 | <glyph unicode="" d="M0 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t231.5 47.5q122 0 232.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-218 -217.5t-300 -80t-299.5 80t-217.5 217.5t-80 299.5zM200 600l402 -294l-2 194h300l2 201h-300v197z" /> 162 | <glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600h200v-300h200v300h200l-300 400z" /> 163 | <glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600l300 -400l300 400h-200v300h-200v-300h-200z" /> 164 | <glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM254 780q-8 -33 5.5 -92.5t7.5 -87.5q0 -9 17 -44t16 -60 q12 0 23 -5.5t23 -15t20 -13.5q24 -12 108 -42q22 -8 53 -31.5t59.5 -38.5t57.5 -11q8 -18 -15 -55t-20 -57q42 -71 87 -80q0 -6 -3 -15.5t-3.5 -14.5t4.5 -17q104 -3 221 112q30 29 47 47t34.5 49t20.5 62q-14 9 -37 9.5t-36 7.5q-14 7 -49 15t-52 19q-9 0 -39.5 -0.5 t-46.5 -1.5t-39 -6.5t-39 -16.5q-50 -35 -66 -12q-4 2 -3.5 25.5t0.5 25.5q-6 13 -26.5 17t-24.5 7q2 22 -2 41t-16.5 28t-38.5 -20q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q12 -19 32 -37.5t34 -27.5l14 -8q0 3 9.5 39.5t5.5 57.5 q-4 23 14.5 44.5t22.5 31.5q5 14 10 35t8.5 31t15.5 22.5t34 21.5q-6 18 10 37q8 0 23.5 -1.5t24.5 -1.5t20.5 4.5t20.5 15.5q-10 23 -30.5 42.5t-38 30t-49 26.5t-43.5 23q11 39 2 44q31 -13 58 -14.5t39 3.5l11 4q7 36 -16.5 53.5t-64.5 28.5t-56 23q-19 -3 -37 0 q-15 -12 -36.5 -21t-34.5 -12t-44 -8t-39 -6q-15 -3 -45.5 0.5t-45.5 -2.5q-21 -7 -52 -26.5t-34 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -90.5t-29.5 -79.5zM518 916q3 12 16 30t16 25q10 -10 18.5 -10t14 6t14.5 14.5t16 12.5q0 -24 17 -66.5t17 -43.5 q-9 2 -31 5t-36 5t-32 8t-30 14zM692 1003h1h-1z" /> 165 | <glyph unicode="" d="M0 164.5q0 21.5 15 37.5l600 599q-33 101 6 201.5t135 154.5q164 92 306 -9l-259 -138l145 -232l251 126q13 -175 -151 -267q-123 -70 -253 -23l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5z" /> 166 | <glyph unicode="" horiz-adv-x="1220" d="M0 196v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 596v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5zM0 996v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM600 596h500v100h-500v-100zM800 196h300v100h-300v-100zM900 996h200v100h-200v-100z" /> 167 | <glyph unicode="" d="M100 1100v100h1000v-100h-1000zM150 1000h900l-350 -500v-300l-200 -200v500z" /> 168 | <glyph unicode="" d="M0 200v200h1200v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500z M500 1000h200v100h-200v-100z" /> 169 | <glyph unicode="" d="M0 0v400l129 -129l200 200l142 -142l-200 -200l129 -129h-400zM0 800l129 129l200 -200l142 142l-200 200l129 129h-400v-400zM729 329l142 142l200 -200l129 129v-400h-400l129 129zM729 871l200 200l-129 129h400v-400l-129 129l-200 -200z" /> 170 | <glyph unicode="" d="M0 596q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 596q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM291 655 q0 23 15.5 38.5t38.5 15.5t39 -16t16 -38q0 -23 -16 -39t-39 -16q-22 0 -38 16t-16 39zM400 850q0 22 16 38.5t39 16.5q22 0 38 -16t16 -39t-16 -39t-38 -16q-23 0 -39 16.5t-16 38.5zM514 609q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 22 16 38.5t39 16.5 q22 0 38 -16t16 -39t-16 -39t-38 -16q-14 0 -29 10l-55 -145q17 -22 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5zM800 655q0 22 16 38t39 16t38.5 -15.5t15.5 -38.5t-16 -39t-38 -16q-23 0 -39 16t-16 39z" /> 171 | <glyph unicode="" d="M-40 375q-13 -95 35 -173q35 -57 94 -89t129 -32q63 0 119 28q33 16 65 40.5t52.5 45.5t59.5 64q40 44 57 61l394 394q35 35 47 84t-3 96q-27 87 -117 104q-20 2 -29 2q-46 0 -78.5 -16.5t-67.5 -51.5l-389 -396l-7 -7l69 -67l377 373q20 22 39 38q23 23 50 23 q38 0 53 -36q16 -39 -20 -75l-547 -547q-52 -52 -125 -52q-55 0 -100 33t-54 96q-5 35 2.5 66t31.5 63t42 50t56 54q24 21 44 41l348 348q52 52 82.5 79.5t84 54t107.5 26.5q25 0 48 -4q95 -17 154 -94.5t51 -175.5q-7 -101 -98 -192l-252 -249l-253 -256l7 -7l69 -60 l517 511q67 67 95 157t11 183q-16 87 -67 154t-130 103q-69 33 -152 33q-107 0 -197 -55q-40 -24 -111 -95l-512 -512q-68 -68 -81 -163z" /> 172 | <glyph unicode="" d="M80 784q0 131 98.5 229.5t230.5 98.5q143 0 241 -129q103 129 246 129q129 0 226 -98.5t97 -229.5q0 -46 -17.5 -91t-61 -99t-77 -89.5t-104.5 -105.5q-197 -191 -293 -322l-17 -23l-16 23q-43 58 -100 122.5t-92 99.5t-101 100q-71 70 -104.5 105.5t-77 89.5t-61 99 t-17.5 91zM250 784q0 -27 30.5 -70t61.5 -75.5t95 -94.5l22 -22q93 -90 190 -201q82 92 195 203l12 12q64 62 97.5 97t64.5 79t31 72q0 71 -48 119.5t-105 48.5q-74 0 -132 -83l-118 -171l-114 174q-51 80 -123 80q-60 0 -109.5 -49.5t-49.5 -118.5z" /> 173 | <glyph unicode="" d="M57 353q0 -95 66 -159l141 -142q68 -66 159 -66q93 0 159 66l283 283q66 66 66 159t-66 159l-141 141q-8 9 -19 17l-105 -105l212 -212l-389 -389l-247 248l95 95l-18 18q-46 45 -75 101l-55 -55q-66 -66 -66 -159zM269 706q0 -93 66 -159l141 -141q7 -7 19 -17l105 105 l-212 212l389 389l247 -247l-95 -96l18 -17q47 -49 77 -100l29 29q35 35 62.5 88t27.5 96q0 93 -66 159l-141 141q-66 66 -159 66q-95 0 -159 -66l-283 -283q-66 -64 -66 -159z" /> 174 | <glyph unicode="" d="M200 100v953q0 21 30 46t81 48t129 38t163 15t162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5zM300 300h600v700h-600v-700zM496 150q0 -43 30.5 -73.5t73.5 -30.5t73.5 30.5t30.5 73.5t-30.5 73.5t-73.5 30.5 t-73.5 -30.5t-30.5 -73.5z" /> 175 | <glyph unicode="" d="M0 0l303 380l207 208l-210 212h300l267 279l-35 36q-15 14 -15 35t15 35q14 15 35 15t35 -15l283 -282q15 -15 15 -36t-15 -35q-14 -15 -35 -15t-35 15l-36 35l-279 -267v-300l-212 210l-208 -207z" /> 176 | <glyph unicode="" d="M295 433h139q5 -77 48.5 -126.5t117.5 -64.5v335q-6 1 -15.5 4t-11.5 3q-46 14 -79 26.5t-72 36t-62.5 52t-40 72.5t-16.5 99q0 92 44 159.5t109 101t144 40.5v78h100v-79q38 -4 72.5 -13.5t75.5 -31.5t71 -53.5t51.5 -84t24.5 -118.5h-159q-8 72 -35 109.5t-101 50.5 v-307l64 -14q34 -7 64 -16.5t70 -31.5t67.5 -52t47.5 -80.5t20 -112.5q0 -139 -89 -224t-244 -96v-77h-100v78q-152 17 -237 104q-40 40 -52.5 93.5t-15.5 139.5zM466 889q0 -29 8 -51t16.5 -34t29.5 -22.5t31 -13.5t38 -10q7 -2 11 -3v274q-61 -8 -97.5 -37.5t-36.5 -102.5 zM700 237q170 18 170 151q0 64 -44 99.5t-126 60.5v-311z" /> 177 | <glyph unicode="" d="M100 600v100h166q-24 49 -44 104q-10 26 -14.5 55.5t-3 72.5t25 90t68.5 87q97 88 263 88q129 0 230 -89t101 -208h-153q0 52 -34 89.5t-74 51.5t-76 14q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -28 16.5 -69.5t28 -62.5t41.5 -72h241v-100h-197q8 -50 -2.5 -115 t-31.5 -94q-41 -59 -99 -113q35 11 84 18t70 7q33 1 103 -16t103 -17q76 0 136 30l50 -147q-41 -25 -80.5 -36.5t-59 -13t-61.5 -1.5q-23 0 -128 33t-155 29q-39 -4 -82 -17t-66 -25l-24 -11l-55 145l16.5 11t15.5 10t13.5 9.5t14.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221z" /> 178 | <glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM602 900l298 300l298 -300h-198v-900h-200v900h-198z" /> 179 | <glyph unicode="" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v200h100v-100h200v-100h-300zM700 400v100h300v-200h-99v-100h-100v100h99v100h-200zM700 700v500h300v-500h-100v100h-100v-100h-100zM801 900h100v200h-100v-200z" /> 180 | <glyph unicode="" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v500h300v-500h-100v100h-100v-100h-100zM700 700v200h100v-100h200v-100h-300zM700 1100v100h300v-200h-99v-100h-100v100h99v100h-200zM801 200h100v200h-100v-200z" /> 181 | <glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 100v400h300v-500h-100v100h-200zM800 1100v100h200v-500h-100v400h-100zM901 200h100v200h-100v-200z" /> 182 | <glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 400v100h200v-500h-100v400h-100zM800 800v400h300v-500h-100v100h-200zM901 900h100v200h-100v-200z" /> 183 | <glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h500v-200h-500zM700 400v200h400v-200h-400zM700 700v200h300v-200h-300zM700 1000v200h200v-200h-200z" /> 184 | <glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h200v-200h-200zM700 400v200h300v-200h-300zM700 700v200h400v-200h-400zM700 1000v200h500v-200h-500z" /> 185 | <glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q162 0 281 -118.5t119 -281.5v-300q0 -165 -118.5 -282.5t-281.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500z" /> 186 | <glyph unicode="" d="M0 400v300q0 163 119 281.5t281 118.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-163 0 -281.5 117.5t-118.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM400 300l333 250l-333 250v-500z" /> 187 | <glyph unicode="" d="M0 400v300q0 163 117.5 281.5t282.5 118.5h300q163 0 281.5 -119t118.5 -281v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 700l250 -333l250 333h-500z" /> 188 | <glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -162 -118.5 -281t-281.5 -119h-300q-165 0 -282.5 118.5t-117.5 281.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 400h500l-250 333z" /> 189 | <glyph unicode="" d="M0 400v300h300v200l400 -350l-400 -350v200h-300zM500 0v200h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-500v200h400q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-400z" /> 190 | <glyph unicode="" d="M217 519q8 -19 31 -19h302q-155 -438 -160 -458q-5 -21 4 -32l9 -8h9q14 0 26 15q11 13 274.5 321.5t264.5 308.5q14 19 5 36q-8 17 -31 17l-301 -1q1 4 78 219.5t79 227.5q2 15 -5 27l-9 9h-9q-15 0 -25 -16q-4 -6 -98 -111.5t-228.5 -257t-209.5 -237.5q-16 -19 -6 -41 z" /> 191 | <glyph unicode="" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q47 0 100 15v185h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h500v185q-14 4 -114 7.5t-193 5.5l-93 2q-165 0 -282.5 -117.5t-117.5 -282.5v-300zM600 400v300h300v200l400 -350l-400 -350v200h-300z " /> 192 | <glyph unicode="" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q163 0 281.5 117.5t118.5 282.5v98l-78 73l-122 -123v-148q0 -41 -29.5 -70.5t-70.5 -29.5h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h156l118 122l-74 78h-100q-165 0 -282.5 -117.5t-117.5 -282.5 v-300zM496 709l353 342l-149 149h500v-500l-149 149l-342 -353z" /> 193 | <glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM406 600 q0 80 57 137t137 57t137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137z" /> 194 | <glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 800l445 -500l450 500h-295v400h-300v-400h-300zM900 150h100v50h-100v-50z" /> 195 | <glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 700h300v-300h300v300h295l-445 500zM900 150h100v50h-100v-50z" /> 196 | <glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 705l305 -305l596 596l-154 155l-442 -442l-150 151zM900 150h100v50h-100v-50z" /> 197 | <glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 988l97 -98l212 213l-97 97zM200 400l697 1l3 699l-250 -239l-149 149l-212 -212l149 -149zM900 150h100v50h-100v-50z" /> 198 | <glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM200 612l212 -212l98 97l-213 212zM300 1200l239 -250l-149 -149l212 -212l149 148l249 -237l-1 697zM900 150h100v50h-100v-50z" /> 199 | <glyph unicode="" d="M23 415l1177 784v-1079l-475 272l-310 -393v416h-392zM494 210l672 938l-672 -712v-226z" /> 200 | <glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-850q0 -21 -15 -35.5t-35 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200z" /> 201 | <glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-218l-276 -275l-120 120l-126 -127h-378v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM581 306l123 123l120 -120l353 352l123 -123l-475 -476zM600 1000h100v200h-100v-200z" /> 202 | <glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-269l-103 -103l-170 170l-298 -298h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200zM700 133l170 170l-170 170l127 127l170 -170l170 170l127 -128l-170 -169l170 -170 l-127 -127l-170 170l-170 -170z" /> 203 | <glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-300h-400v-200h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300l300 -300l300 300h-200v300h-200v-300h-200zM600 1000v200h100v-200h-100z" /> 204 | <glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-402l-200 200l-298 -298h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300h200v-300h200v300h200l-300 300zM600 1000v200h100v-200h-100z" /> 205 | <glyph unicode="" d="M0 250q0 -21 14.5 -35.5t35.5 -14.5h1100q21 0 35.5 14.5t14.5 35.5v550h-1200v-550zM0 900h1200v150q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 300v200h400v-200h-400z" /> 206 | <glyph unicode="" d="M0 400l300 298v-198h400v-200h-400v-198zM100 800v200h100v-200h-100zM300 800v200h100v-200h-100zM500 800v200h400v198l300 -298l-300 -298v198h-400zM800 300v200h100v-200h-100zM1000 300h100v200h-100v-200z" /> 207 | <glyph unicode="" d="M100 700v400l50 100l50 -100v-300h100v300l50 100l50 -100v-300h100v300l50 100l50 -100v-400l-100 -203v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447zM800 597q0 -29 10.5 -55.5t25 -43t29 -28.5t25.5 -18l10 -5v-397q0 -21 14.5 -35.5 t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v1106q0 31 -18 40.5t-44 -7.5l-276 -116q-25 -17 -43.5 -51.5t-18.5 -65.5v-359z" /> 208 | <glyph unicode="" d="M100 0h400v56q-75 0 -87.5 6t-12.5 44v394h500v-394q0 -38 -12.5 -44t-87.5 -6v-56h400v56q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v888q0 22 25 34.5t50 13.5l25 2v56h-400v-56q75 0 87.5 -6t12.5 -44v-394h-500v394q0 38 12.5 44t87.5 6v56h-400v-56q4 0 11 -0.5 t24 -3t30 -7t24 -15t11 -24.5v-888q0 -22 -25 -34.5t-50 -13.5l-25 -2v-56z" /> 209 | <glyph unicode="" d="M0 300q0 -41 29.5 -70.5t70.5 -29.5h300q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-300q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM100 100h400l200 200h105l295 98v-298h-425l-100 -100h-375zM100 300v200h300v-200h-300zM100 600v200h300v-200h-300z M100 1000h400l200 -200v-98l295 98h105v200h-425l-100 100h-375zM700 402v163l400 133v-163z" /> 210 | <glyph unicode="" d="M16.5 974.5q0.5 -21.5 16 -90t46.5 -140t104 -177.5t175 -208q103 -103 207.5 -176t180 -103.5t137 -47t92.5 -16.5l31 1l163 162q17 18 13.5 41t-22.5 37l-192 136q-19 14 -45 12t-42 -19l-118 -118q-142 101 -268 227t-227 268l118 118q17 17 20 41.5t-11 44.5 l-139 194q-14 19 -36.5 22t-40.5 -14l-162 -162q-1 -11 -0.5 -32.5z" /> 211 | <glyph unicode="" d="M0 50v212q0 20 10.5 45.5t24.5 39.5l365 303v50q0 4 1 10.5t12 22.5t30 28.5t60 23t97 10.5t97 -10t60 -23.5t30 -27.5t12 -24l1 -10v-50l365 -303q14 -14 24.5 -39.5t10.5 -45.5v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-20 0 -35 14.5t-15 35.5zM0 712 q0 -21 14.5 -33.5t34.5 -8.5l202 33q20 4 34.5 21t14.5 38v146q141 24 300 24t300 -24v-146q0 -21 14.5 -38t34.5 -21l202 -33q20 -4 34.5 8.5t14.5 33.5v200q-6 8 -19 20.5t-63 45t-112 57t-171 45t-235 20.5q-92 0 -175 -10.5t-141.5 -27t-108.5 -36.5t-81.5 -40 t-53.5 -36.5t-31 -27.5l-9 -10v-200z" /> 212 | <glyph unicode="" d="M100 0v100h1100v-100h-1100zM175 200h950l-125 150v250l100 100v400h-100v-200h-100v200h-200v-200h-100v200h-200v-200h-100v200h-100v-400l100 -100v-250z" /> 213 | <glyph unicode="" d="M100 0h300v400q0 41 -29.5 70.5t-70.5 29.5h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-400zM500 0v1000q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-1000h-300zM900 0v700q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-700h-300z" /> 214 | <glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" /> 215 | <glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h100v200h100v-200h100v500h-100v-200h-100v200h-100v-500zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" /> 216 | <glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v100h-200v300h200v100h-300v-500zM600 300h300v100h-200v300h200v100h-300v-500z" /> 217 | <glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 550l300 -150v300zM600 400l300 150l-300 150v-300z" /> 218 | <glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300v500h700v-500h-700zM300 400h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130v-300zM575 549 q0 -65 27 -107t68 -42h130v300h-130q-38 0 -66.5 -43t-28.5 -108z" /> 219 | <glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" /> 220 | <glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v400h-200v100h-100v-500zM301 400v200h100v-200h-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" /> 221 | <glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 700v100h300v-300h-99v-100h-100v100h99v200h-200zM201 300v100h100v-100h-100zM601 300v100h100v-100h-100z M700 700v100h200v-500h-100v400h-100z" /> 222 | <glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 500v200 l100 100h300v-100h-300v-200h300v-100h-300z" /> 223 | <glyph unicode="" d="M0 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 400v400h300 l100 -100v-100h-100v100h-200v-100h200v-100h-200v-100h-100zM700 400v100h100v-100h-100z" /> 224 | <glyph unicode="" d="M-14 494q0 -80 56.5 -137t135.5 -57h222v300h400v-300h128q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200h200v300h200v-300h200 l-300 -300z" /> 225 | <glyph unicode="" d="M-14 494q0 -80 56.5 -137t135.5 -57h8l414 414l403 -403q94 26 154.5 104.5t60.5 178.5q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200l300 300 l300 -300h-200v-300h-200v300h-200z" /> 226 | <glyph unicode="" d="M100 200h400v-155l-75 -45h350l-75 45v155h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170z" /> 227 | <glyph unicode="" d="M121 700q0 -53 28.5 -97t75.5 -65q-4 -16 -4 -38q0 -74 52.5 -126.5t126.5 -52.5q56 0 100 30v-306l-75 -45h350l-75 45v306q46 -30 100 -30q74 0 126.5 52.5t52.5 126.5q0 24 -9 55q50 32 79.5 83t29.5 112q0 90 -61.5 155.5t-150.5 71.5q-26 89 -99.5 145.5 t-167.5 56.5q-116 0 -197.5 -81.5t-81.5 -197.5q0 -4 1 -11.5t1 -11.5q-14 2 -23 2q-74 0 -126.5 -52.5t-52.5 -126.5z" /> 228 | </font> 229 | </defs></svg> -------------------------------------------------------------------------------- /app/public/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gregjopa/express-app-testing-demo/c68df7b899b23f74d8dd8a0862fd4e512ec0f6f5/app/public/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /app/public/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gregjopa/express-app-testing-demo/c68df7b899b23f74d8dd8a0862fd4e512ec0f6f5/app/public/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /app/public/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gregjopa/express-app-testing-demo/c68df7b899b23f74d8dd8a0862fd4e512ec0f6f5/app/public/images/favicon.ico -------------------------------------------------------------------------------- /app/route.js: -------------------------------------------------------------------------------- 1 | const formValidator = require('./form_validator'); 2 | const photoModel = require('./photo_model'); 3 | 4 | function route(app) { 5 | app.get('/', (req, res) => { 6 | const tags = req.query.tags; 7 | const tagmode = req.query.tagmode; 8 | 9 | const ejsLocalVariables = { 10 | tagsParameter: tags || '', 11 | tagmodeParameter: tagmode || '', 12 | photos: [], 13 | searchResults: false, 14 | invalidParameters: false 15 | }; 16 | 17 | // if no input params are passed in then render the view with out querying the api 18 | if (!tags && !tagmode) { 19 | return res.render('index', ejsLocalVariables); 20 | } 21 | 22 | // validate query parameters 23 | if (!formValidator.hasValidFlickrAPIParams(tags, tagmode)) { 24 | ejsLocalVariables.invalidParameters = true; 25 | return res.render('index', ejsLocalVariables); 26 | } 27 | 28 | // get photos from flickr public feed api 29 | return photoModel 30 | .getFlickrPhotos(tags, tagmode) 31 | .then(photos => { 32 | ejsLocalVariables.photos = photos; 33 | ejsLocalVariables.searchResults = true; 34 | return res.render('index', ejsLocalVariables); 35 | }) 36 | .catch(error => { 37 | return res.status(500).send({ error }); 38 | }); 39 | }); 40 | } 41 | 42 | module.exports = route; 43 | -------------------------------------------------------------------------------- /app/server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const favicon = require('serve-favicon'); 3 | const path = require('path'); 4 | 5 | const app = express(); 6 | 7 | // public assets 8 | app.use(express.static(path.join(__dirname, 'public'))); 9 | app.use(favicon(path.join(__dirname, 'public/images', 'favicon.ico'))); 10 | app.use('/coverage', express.static(path.join(__dirname, '..', 'coverage'))); 11 | 12 | // ejs for view templates 13 | app.engine('.html', require('ejs').__express); 14 | app.set('views', path.join(__dirname, 'views')); 15 | app.set('view engine', 'html'); 16 | 17 | // load route 18 | require('./route')(app); 19 | 20 | // server 21 | const port = process.env.PORT || 3000; 22 | app.server = app.listen(port); 23 | console.log(`listening on port ${port}`); 24 | 25 | module.exports = app; 26 | -------------------------------------------------------------------------------- /app/views/_footer.html: -------------------------------------------------------------------------------- 1 | <footer class="footer"> 2 | <div class="container"> 3 | <br> 4 | <p class="text-center"> 5 | Developed By <a href="https://twitter.com/gregjopa" target="_blank">@gregjopa</a>. 6 | The source code for this demo is available on github: 7 | <br><a href="https://github.com/gregjopa/express-app-testing-demo" target="_blank"> 8 | https://github.com/gregjopa/express-app-testing-demo 9 | </a> 10 | 11 | </p> 12 | </div> 13 | </footer> 14 | </body> 15 | </html> 16 | -------------------------------------------------------------------------------- /app/views/_header.html: -------------------------------------------------------------------------------- 1 | <!DOCTYPE html> 2 | <html lang="en"> 3 | <head> 4 | <meta charset="utf-8"> 5 | <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 | <title>Express App Testing Demo 7 | 8 | 9 | 10 | 11 | 26 | -------------------------------------------------------------------------------- /app/views/_search_form.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | 6 | 8 | 9 |
10 |
11 | 12 | 23 | 24 |
25 | 26 |
27 |
28 | -------------------------------------------------------------------------------- /app/views/_search_results.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |

Search Results

6 |
7 |
8 | 9 | <% if (photos.length) { %> 10 | 11 | 21 | 22 | <% } else { %> 23 |
No results
24 | <% } %> 25 | 26 |
27 | 28 |
29 | -------------------------------------------------------------------------------- /app/views/index.html: -------------------------------------------------------------------------------- 1 | <%-include('_header.html') %> 2 | 3 | 4 |
5 | 6 | <%- include('_search_form.html') %> 7 | 8 | <% if (invalidParameters) { %> 9 |
10 | Invalid value for "tags" or "tagmode" input parameters

11 | Tags should be formatted as a comma delimited list containing only letters, commas, and spaces. 12 | Tag Mode must equal "all" or "any". 13 |
14 | <% } %> 15 | 16 | <% if (searchResults) { %> 17 | <%- include('_search_results.html') %> 18 | <% } %> 19 | 20 |
21 | 22 | 23 | <%- include('_footer.html') %> 24 | -------------------------------------------------------------------------------- /coverage/clover.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /coverage/coverage-final.json: -------------------------------------------------------------------------------- 1 | {"/Users/gregjopa/projects/express-app-testing-demo/app/form_validator.js": {"path":"/Users/gregjopa/projects/express-app-testing-demo/app/form_validator.js","statementMap":{"0":{"start":{"line":3,"column":34},"end":{"line":3,"column":50}},"1":{"start":{"line":4,"column":2},"end":{"line":4,"column":45}},"2":{"start":{"line":8,"column":2},"end":{"line":8,"column":44}},"3":{"start":{"line":12,"column":2},"end":{"line":12,"column":68}},"4":{"start":{"line":15,"column":0},"end":{"line":19,"column":2}}},"fnMap":{"0":{"name":"isValidCommaDelimitedList","decl":{"start":{"line":1,"column":9},"end":{"line":1,"column":34}},"loc":{"start":{"line":1,"column":42},"end":{"line":5,"column":1}},"line":1},"1":{"name":"isValidTagmode","decl":{"start":{"line":7,"column":9},"end":{"line":7,"column":23}},"loc":{"start":{"line":7,"column":31},"end":{"line":9,"column":1}},"line":7},"2":{"name":"hasValidFlickrAPIParams","decl":{"start":{"line":11,"column":9},"end":{"line":11,"column":32}},"loc":{"start":{"line":11,"column":48},"end":{"line":13,"column":1}},"line":11}},"branchMap":{"0":{"loc":{"start":{"line":8,"column":9},"end":{"line":8,"column":43}},"type":"binary-expr","locations":[{"start":{"line":8,"column":9},"end":{"line":8,"column":24}},{"start":{"line":8,"column":28},"end":{"line":8,"column":43}}],"line":8},"1":{"loc":{"start":{"line":12,"column":9},"end":{"line":12,"column":67}},"type":"binary-expr","locations":[{"start":{"line":12,"column":9},"end":{"line":12,"column":40}},{"start":{"line":12,"column":44},"end":{"line":12,"column":67}}],"line":12}},"s":{"0":10,"1":10,"2":7,"3":6,"4":2},"f":{"0":10,"1":7,"2":6},"b":{"0":[7,3],"1":[6,4]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"1722d59bc0f4dc4cfd9b46eebc82442fb9920633"} 2 | ,"/Users/gregjopa/projects/express-app-testing-demo/app/jsonp_helper.js": {"path":"/Users/gregjopa/projects/express-app-testing-demo/app/jsonp_helper.js","statementMap":{"0":{"start":{"line":2,"column":2},"end":{"line":14,"column":3}},"1":{"start":{"line":3,"column":21},"end":{"line":3,"column":44}},"2":{"start":{"line":4,"column":19},"end":{"line":4,"column":46}},"3":{"start":{"line":5,"column":21},"end":{"line":5,"column":66}},"4":{"start":{"line":8,"column":4},"end":{"line":8,"column":49}},"5":{"start":{"line":10,"column":4},"end":{"line":10,"column":34}},"6":{"start":{"line":12,"column":18},"end":{"line":12,"column":76}},"7":{"start":{"line":13,"column":4},"end":{"line":13,"column":16}},"8":{"start":{"line":17,"column":0},"end":{"line":19,"column":2}}},"fnMap":{"0":{"name":"parseJSONP","decl":{"start":{"line":1,"column":9},"end":{"line":1,"column":19}},"loc":{"start":{"line":1,"column":31},"end":{"line":15,"column":1}},"line":1}},"branchMap":{},"s":{"0":5,"1":5,"2":5,"3":5,"4":5,"5":5,"6":2,"7":2,"8":4},"f":{"0":5},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"543520d99e856ae171b41b05a386ab3f9bdee7f0"} 3 | ,"/Users/gregjopa/projects/express-app-testing-demo/app/photo_model.js": {"path":"/Users/gregjopa/projects/express-app-testing-demo/app/photo_model.js","statementMap":{"0":{"start":{"line":1,"column":12},"end":{"line":1,"column":26}},"1":{"start":{"line":2,"column":20},"end":{"line":2,"column":42}},"2":{"start":{"line":3,"column":20},"end":{"line":3,"column":45}},"3":{"start":{"line":6,"column":13},"end":{"line":6,"column":69}},"4":{"start":{"line":8,"column":18},"end":{"line":13,"column":3}},"5":{"start":{"line":15,"column":2},"end":{"line":24,"column":5}},"6":{"start":{"line":16,"column":22},"end":{"line":16,"column":59}},"7":{"start":{"line":18,"column":4},"end":{"line":21,"column":7}},"8":{"start":{"line":19,"column":6},"end":{"line":19,"column":64}},"9":{"start":{"line":20,"column":6},"end":{"line":20,"column":64}},"10":{"start":{"line":23,"column":4},"end":{"line":23,"column":27}},"11":{"start":{"line":27,"column":0},"end":{"line":29,"column":2}}},"fnMap":{"0":{"name":"getFlickrPhotos","decl":{"start":{"line":5,"column":9},"end":{"line":5,"column":24}},"loc":{"start":{"line":5,"column":40},"end":{"line":25,"column":1}},"line":5},"1":{"name":"(anonymous_1)","decl":{"start":{"line":15,"column":27},"end":{"line":15,"column":28}},"loc":{"start":{"line":15,"column":39},"end":{"line":24,"column":3}},"line":15},"2":{"name":"(anonymous_2)","decl":{"start":{"line":18,"column":28},"end":{"line":18,"column":29}},"loc":{"start":{"line":18,"column":37},"end":{"line":21,"column":5}},"line":18}},"branchMap":{},"s":{"0":3,"1":3,"2":3,"3":3,"4":3,"5":3,"6":2,"7":1,"8":2,"9":2,"10":1,"11":3},"f":{"0":3,"1":2,"2":2},"b":{},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"a794f2ec1d13e41f6f46215ab32aaeaef94160c5"} 4 | ,"/Users/gregjopa/projects/express-app-testing-demo/app/route.js": {"path":"/Users/gregjopa/projects/express-app-testing-demo/app/route.js","statementMap":{"0":{"start":{"line":1,"column":22},"end":{"line":1,"column":49}},"1":{"start":{"line":2,"column":19},"end":{"line":2,"column":43}},"2":{"start":{"line":5,"column":2},"end":{"line":39,"column":5}},"3":{"start":{"line":6,"column":17},"end":{"line":6,"column":31}},"4":{"start":{"line":7,"column":20},"end":{"line":7,"column":37}},"5":{"start":{"line":9,"column":30},"end":{"line":15,"column":5}},"6":{"start":{"line":18,"column":4},"end":{"line":20,"column":5}},"7":{"start":{"line":19,"column":6},"end":{"line":19,"column":52}},"8":{"start":{"line":23,"column":4},"end":{"line":26,"column":5}},"9":{"start":{"line":24,"column":6},"end":{"line":24,"column":49}},"10":{"start":{"line":25,"column":6},"end":{"line":25,"column":52}},"11":{"start":{"line":29,"column":4},"end":{"line":38,"column":9}},"12":{"start":{"line":32,"column":8},"end":{"line":32,"column":42}},"13":{"start":{"line":33,"column":8},"end":{"line":33,"column":47}},"14":{"start":{"line":34,"column":8},"end":{"line":34,"column":54}},"15":{"start":{"line":37,"column":8},"end":{"line":37,"column":47}},"16":{"start":{"line":42,"column":0},"end":{"line":42,"column":23}}},"fnMap":{"0":{"name":"route","decl":{"start":{"line":4,"column":9},"end":{"line":4,"column":14}},"loc":{"start":{"line":4,"column":20},"end":{"line":40,"column":1}},"line":4},"1":{"name":"(anonymous_1)","decl":{"start":{"line":5,"column":15},"end":{"line":5,"column":16}},"loc":{"start":{"line":5,"column":29},"end":{"line":39,"column":3}},"line":5},"2":{"name":"(anonymous_2)","decl":{"start":{"line":31,"column":12},"end":{"line":31,"column":13}},"loc":{"start":{"line":31,"column":22},"end":{"line":35,"column":7}},"line":31},"3":{"name":"(anonymous_3)","decl":{"start":{"line":36,"column":13},"end":{"line":36,"column":14}},"loc":{"start":{"line":36,"column":22},"end":{"line":38,"column":7}},"line":36}},"branchMap":{"0":{"loc":{"start":{"line":10,"column":21},"end":{"line":10,"column":31}},"type":"binary-expr","locations":[{"start":{"line":10,"column":21},"end":{"line":10,"column":25}},{"start":{"line":10,"column":29},"end":{"line":10,"column":31}}],"line":10},"1":{"loc":{"start":{"line":11,"column":24},"end":{"line":11,"column":37}},"type":"binary-expr","locations":[{"start":{"line":11,"column":24},"end":{"line":11,"column":31}},{"start":{"line":11,"column":35},"end":{"line":11,"column":37}}],"line":11},"2":{"loc":{"start":{"line":18,"column":4},"end":{"line":20,"column":5}},"type":"if","locations":[{"start":{"line":18,"column":4},"end":{"line":20,"column":5}},{"start":{"line":18,"column":4},"end":{"line":20,"column":5}}],"line":18},"3":{"loc":{"start":{"line":18,"column":8},"end":{"line":18,"column":25}},"type":"binary-expr","locations":[{"start":{"line":18,"column":8},"end":{"line":18,"column":13}},{"start":{"line":18,"column":17},"end":{"line":18,"column":25}}],"line":18},"4":{"loc":{"start":{"line":23,"column":4},"end":{"line":26,"column":5}},"type":"if","locations":[{"start":{"line":23,"column":4},"end":{"line":26,"column":5}},{"start":{"line":23,"column":4},"end":{"line":26,"column":5}}],"line":23}},"s":{"0":1,"1":1,"2":1,"3":4,"4":4,"5":4,"6":4,"7":1,"8":3,"9":1,"10":1,"11":2,"12":1,"13":1,"14":1,"15":1,"16":1},"f":{"0":1,"1":4,"2":1,"3":1},"b":{"0":[4,1],"1":[4,1],"2":[1,3],"3":[4,1],"4":[1,2]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"3422955b5004d57455657fed0c27df7f8bf8b53c"} 5 | ,"/Users/gregjopa/projects/express-app-testing-demo/app/server.js": {"path":"/Users/gregjopa/projects/express-app-testing-demo/app/server.js","statementMap":{"0":{"start":{"line":1,"column":16},"end":{"line":1,"column":34}},"1":{"start":{"line":2,"column":16},"end":{"line":2,"column":40}},"2":{"start":{"line":3,"column":13},"end":{"line":3,"column":28}},"3":{"start":{"line":5,"column":12},"end":{"line":5,"column":21}},"4":{"start":{"line":8,"column":0},"end":{"line":8,"column":56}},"5":{"start":{"line":9,"column":0},"end":{"line":9,"column":71}},"6":{"start":{"line":10,"column":0},"end":{"line":10,"column":77}},"7":{"start":{"line":13,"column":0},"end":{"line":13,"column":46}},"8":{"start":{"line":14,"column":0},"end":{"line":14,"column":48}},"9":{"start":{"line":15,"column":0},"end":{"line":15,"column":31}},"10":{"start":{"line":18,"column":0},"end":{"line":18,"column":24}},"11":{"start":{"line":21,"column":13},"end":{"line":21,"column":37}},"12":{"start":{"line":22,"column":0},"end":{"line":22,"column":30}},"13":{"start":{"line":23,"column":0},"end":{"line":23,"column":41}},"14":{"start":{"line":25,"column":0},"end":{"line":25,"column":21}}},"fnMap":{},"branchMap":{"0":{"loc":{"start":{"line":21,"column":13},"end":{"line":21,"column":37}},"type":"binary-expr","locations":[{"start":{"line":21,"column":13},"end":{"line":21,"column":29}},{"start":{"line":21,"column":33},"end":{"line":21,"column":37}}],"line":21}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":1,"8":1,"9":1,"10":1,"11":1,"12":1,"13":1,"14":1},"f":{},"b":{"0":[1,1]},"_coverageSchema":"1a1c01bbd47fc00a2c39e90264f33305004495a9","hash":"169a1a1855ea74cc4c7eac400da89ee036dc92ae"} 6 | } 7 | -------------------------------------------------------------------------------- /coverage/lcov-report/app.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Code coverage report for app.js 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 |

19 | All files app.js 20 |

21 |
22 |
23 | 100% 24 | Statements 25 | 15/15 26 |
27 |
28 | 50% 29 | Branches 30 | 1/2 31 |
32 |
33 | 100% 34 | Functions 35 | 0/0 36 |
37 |
38 | 100% 39 | Lines 40 | 15/15 41 |
42 |
43 |
44 |
45 |

 46 | 
122 | 
1 47 | 2 48 | 3 49 | 4 50 | 5 51 | 6 52 | 7 53 | 8 54 | 9 55 | 10 56 | 11 57 | 12 58 | 13 59 | 14 60 | 15 61 | 16 62 | 17 63 | 18 64 | 19 65 | 20 66 | 21 67 | 22 68 | 23 69 | 24 70 | 25 71 | 261x 72 | 1x 73 | 1x 74 |   75 | 1x 76 |   77 |   78 | 1x 79 | 1x 80 | 1x 81 |   82 |   83 | 1x 84 | 1x 85 | 1x 86 |   87 |   88 | 1x 89 |   90 |   91 | 1x 92 | 1x 93 | 1x 94 |   95 | 1x 96 |  
const express = require('express');
 97 | const favicon = require('serve-favicon');
 98 | const path = require('path');
 99 |  
100 | const app = express();
101 |  
102 | // public assets
103 | app.use(express.static(path.join(__dirname, 'public')));
104 | app.use(favicon(path.join(__dirname, 'public/images', 'favicon.ico')));
105 | app.use('/coverage', express.static(path.join(__dirname, '..', 'coverage')));
106 |  
107 | // ejs for view templates
108 | app.engine('.html', require('ejs').__express);
109 | app.set('views', path.join(__dirname, 'views'));
110 | app.set('view engine', 'html');
111 |  
112 | // load route
113 | require('./route')(app);
114 |  
115 | // server
116 | const port = process.env.PORT || 3000;
117 | app.server = app.listen(port);
118 | console.log(`listening on port ${port}`);
119 |  
120 | module.exports = app;
121 |  
123 |
124 |
125 | 129 | 130 | 131 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /coverage/lcov-report/base.css: -------------------------------------------------------------------------------- 1 | body, html { 2 | margin:0; padding: 0; 3 | height: 100%; 4 | } 5 | body { 6 | font-family: Helvetica Neue, Helvetica, Arial; 7 | font-size: 14px; 8 | color:#333; 9 | } 10 | .small { font-size: 12px; } 11 | *, *:after, *:before { 12 | -webkit-box-sizing:border-box; 13 | -moz-box-sizing:border-box; 14 | box-sizing:border-box; 15 | } 16 | h1 { font-size: 20px; margin: 0;} 17 | h2 { font-size: 14px; } 18 | pre { 19 | font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; 20 | margin: 0; 21 | padding: 0; 22 | -moz-tab-size: 2; 23 | -o-tab-size: 2; 24 | tab-size: 2; 25 | } 26 | a { color:#0074D9; text-decoration:none; } 27 | a:hover { text-decoration:underline; } 28 | .strong { font-weight: bold; } 29 | .space-top1 { padding: 10px 0 0 0; } 30 | .pad2y { padding: 20px 0; } 31 | .pad1y { padding: 10px 0; } 32 | .pad2x { padding: 0 20px; } 33 | .pad2 { padding: 20px; } 34 | .pad1 { padding: 10px; } 35 | .space-left2 { padding-left:55px; } 36 | .space-right2 { padding-right:20px; } 37 | .center { text-align:center; } 38 | .clearfix { display:block; } 39 | .clearfix:after { 40 | content:''; 41 | display:block; 42 | height:0; 43 | clear:both; 44 | visibility:hidden; 45 | } 46 | .fl { float: left; } 47 | @media only screen and (max-width:640px) { 48 | .col3 { width:100%; max-width:100%; } 49 | .hide-mobile { display:none!important; } 50 | } 51 | 52 | .quiet { 53 | color: #7f7f7f; 54 | color: rgba(0,0,0,0.5); 55 | } 56 | .quiet a { opacity: 0.7; } 57 | 58 | .fraction { 59 | font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; 60 | font-size: 10px; 61 | color: #555; 62 | background: #E8E8E8; 63 | padding: 4px 5px; 64 | border-radius: 3px; 65 | vertical-align: middle; 66 | } 67 | 68 | div.path a:link, div.path a:visited { color: #333; } 69 | table.coverage { 70 | border-collapse: collapse; 71 | margin: 10px 0 0 0; 72 | padding: 0; 73 | } 74 | 75 | table.coverage td { 76 | margin: 0; 77 | padding: 0; 78 | vertical-align: top; 79 | } 80 | table.coverage td.line-count { 81 | text-align: right; 82 | padding: 0 5px 0 20px; 83 | } 84 | table.coverage td.line-coverage { 85 | text-align: right; 86 | padding-right: 10px; 87 | min-width:20px; 88 | } 89 | 90 | table.coverage td span.cline-any { 91 | display: inline-block; 92 | padding: 0 5px; 93 | width: 100%; 94 | } 95 | .missing-if-branch { 96 | display: inline-block; 97 | margin-right: 5px; 98 | border-radius: 3px; 99 | position: relative; 100 | padding: 0 4px; 101 | background: #333; 102 | color: yellow; 103 | } 104 | 105 | .skip-if-branch { 106 | display: none; 107 | margin-right: 10px; 108 | position: relative; 109 | padding: 0 4px; 110 | background: #ccc; 111 | color: white; 112 | } 113 | .missing-if-branch .typ, .skip-if-branch .typ { 114 | color: inherit !important; 115 | } 116 | .coverage-summary { 117 | border-collapse: collapse; 118 | width: 100%; 119 | } 120 | .coverage-summary tr { border-bottom: 1px solid #bbb; } 121 | .keyline-all { border: 1px solid #ddd; } 122 | .coverage-summary td, .coverage-summary th { padding: 10px; } 123 | .coverage-summary tbody { border: 1px solid #bbb; } 124 | .coverage-summary td { border-right: 1px solid #bbb; } 125 | .coverage-summary td:last-child { border-right: none; } 126 | .coverage-summary th { 127 | text-align: left; 128 | font-weight: normal; 129 | white-space: nowrap; 130 | } 131 | .coverage-summary th.file { border-right: none !important; } 132 | .coverage-summary th.pct { } 133 | .coverage-summary th.pic, 134 | .coverage-summary th.abs, 135 | .coverage-summary td.pct, 136 | .coverage-summary td.abs { text-align: right; } 137 | .coverage-summary td.file { white-space: nowrap; } 138 | .coverage-summary td.pic { min-width: 120px !important; } 139 | .coverage-summary tfoot td { } 140 | 141 | .coverage-summary .sorter { 142 | height: 10px; 143 | width: 7px; 144 | display: inline-block; 145 | margin-left: 0.5em; 146 | background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; 147 | } 148 | .coverage-summary .sorted .sorter { 149 | background-position: 0 -20px; 150 | } 151 | .coverage-summary .sorted-desc .sorter { 152 | background-position: 0 -10px; 153 | } 154 | .status-line { height: 10px; } 155 | /* yellow */ 156 | .cbranch-no { background: yellow !important; color: #111; } 157 | /* dark red */ 158 | .red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } 159 | .low .chart { border:1px solid #C21F39 } 160 | .highlighted, 161 | .highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ 162 | background: #C21F39 !important; 163 | } 164 | /* medium red */ 165 | .cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } 166 | /* light red */ 167 | .low, .cline-no { background:#FCE1E5 } 168 | /* light green */ 169 | .high, .cline-yes { background:rgb(230,245,208) } 170 | /* medium green */ 171 | .cstat-yes { background:rgb(161,215,106) } 172 | /* dark green */ 173 | .status-line.high, .high .cover-fill { background:rgb(77,146,33) } 174 | .high .chart { border:1px solid rgb(77,146,33) } 175 | /* dark yellow (gold) */ 176 | .status-line.medium, .medium .cover-fill { background: #f9cd0b; } 177 | .medium .chart { border:1px solid #f9cd0b; } 178 | /* light yellow */ 179 | .medium { background: #fff4c2; } 180 | 181 | .cstat-skip { background: #ddd; color: #111; } 182 | .fstat-skip { background: #ddd; color: #111 !important; } 183 | .cbranch-skip { background: #ddd !important; color: #111; } 184 | 185 | span.cline-neutral { background: #eaeaea; } 186 | 187 | .coverage-summary td.empty { 188 | opacity: .5; 189 | padding-top: 4px; 190 | padding-bottom: 4px; 191 | line-height: 1; 192 | color: #888; 193 | } 194 | 195 | .cover-fill, .cover-empty { 196 | display:inline-block; 197 | height: 12px; 198 | } 199 | .chart { 200 | line-height: 0; 201 | } 202 | .cover-empty { 203 | background: white; 204 | } 205 | .cover-full { 206 | border-right: none !important; 207 | } 208 | pre.prettyprint { 209 | border: none !important; 210 | padding: 0 !important; 211 | margin: 0 !important; 212 | } 213 | .com { color: #999 !important; } 214 | .ignore-none { color: #999; font-weight: normal; } 215 | 216 | .wrapper { 217 | min-height: 100%; 218 | height: auto !important; 219 | height: 100%; 220 | margin: 0 auto -48px; 221 | } 222 | .footer, .push { 223 | height: 48px; 224 | } 225 | -------------------------------------------------------------------------------- /coverage/lcov-report/block-navigation.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | var jumpToCode = (function init() { 3 | // Classes of code we would like to highlight in the file view 4 | var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; 5 | 6 | // Elements to highlight in the file listing view 7 | var fileListingElements = ['td.pct.low']; 8 | 9 | // We don't want to select elements that are direct descendants of another match 10 | var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` 11 | 12 | // Selecter that finds elements on the page to which we can jump 13 | var selector = 14 | fileListingElements.join(', ') + 15 | ', ' + 16 | notSelector + 17 | missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` 18 | 19 | // The NodeList of matching elements 20 | var missingCoverageElements = document.querySelectorAll(selector); 21 | 22 | var currentIndex; 23 | 24 | function toggleClass(index) { 25 | missingCoverageElements 26 | .item(currentIndex) 27 | .classList.remove('highlighted'); 28 | missingCoverageElements.item(index).classList.add('highlighted'); 29 | } 30 | 31 | function makeCurrent(index) { 32 | toggleClass(index); 33 | currentIndex = index; 34 | missingCoverageElements.item(index).scrollIntoView({ 35 | behavior: 'smooth', 36 | block: 'center', 37 | inline: 'center' 38 | }); 39 | } 40 | 41 | function goToPrevious() { 42 | var nextIndex = 0; 43 | if (typeof currentIndex !== 'number' || currentIndex === 0) { 44 | nextIndex = missingCoverageElements.length - 1; 45 | } else if (missingCoverageElements.length > 1) { 46 | nextIndex = currentIndex - 1; 47 | } 48 | 49 | makeCurrent(nextIndex); 50 | } 51 | 52 | function goToNext() { 53 | var nextIndex = 0; 54 | 55 | if ( 56 | typeof currentIndex === 'number' && 57 | currentIndex < missingCoverageElements.length - 1 58 | ) { 59 | nextIndex = currentIndex + 1; 60 | } 61 | 62 | makeCurrent(nextIndex); 63 | } 64 | 65 | return function jump(event) { 66 | switch (event.which) { 67 | case 78: // n 68 | case 74: // j 69 | goToNext(); 70 | break; 71 | case 66: // b 72 | case 75: // k 73 | case 80: // p 74 | goToPrevious(); 75 | break; 76 | } 77 | }; 78 | })(); 79 | window.addEventListener('keydown', jumpToCode); 80 | -------------------------------------------------------------------------------- /coverage/lcov-report/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gregjopa/express-app-testing-demo/c68df7b899b23f74d8dd8a0862fd4e512ec0f6f5/coverage/lcov-report/favicon.png -------------------------------------------------------------------------------- /coverage/lcov-report/form_validator.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Code coverage report for form_validator.js 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 |
21 |
22 |

All files form_validator.js

23 |
24 | 25 |
26 | 100% 27 | Statements 28 | 5/5 29 |
30 | 31 | 32 |
33 | 100% 34 | Branches 35 | 4/4 36 |
37 | 38 | 39 |
40 | 100% 41 | Functions 42 | 3/3 43 |
44 | 45 | 46 |
47 | 100% 48 | Lines 49 | 5/5 50 |
51 | 52 | 53 |
54 |

55 | Press n or j to go to the next uncovered block, b, p or k for the previous block. 56 |

57 |
58 |
59 |

 60 | 
1 61 | 2 62 | 3 63 | 4 64 | 5 65 | 6 66 | 7 67 | 8 68 | 9 69 | 10 70 | 11 71 | 12 72 | 13 73 | 14 74 | 15 75 | 16 76 | 17 77 | 18 78 | 19 79 | 20  80 |   81 | 10x 82 | 10x 83 |   84 |   85 |   86 | 7x 87 |   88 |   89 |   90 | 6x 91 |   92 |   93 | 2x 94 |   95 |   96 |   97 |   98 |  
function isValidCommaDelimitedList(value) {
 99 |   // allow letters, commas, and spaces
100 |   const commaDelimitedListRegEx = /^[A-Za-z,\s]+$/;
101 |   return commaDelimitedListRegEx.test(value);
102 | }
103 |  
104 | function isValidTagmode(value) {
105 |   return value === 'all' || value === 'any';
106 | }
107 |  
108 | function hasValidFlickrAPIParams(tags, tagmode) {
109 |   return isValidCommaDelimitedList(tags) && isValidTagmode(tagmode);
110 | }
111 |  
112 | module.exports = {
113 |   isValidCommaDelimitedList,
114 |   isValidTagmode,
115 |   hasValidFlickrAPIParams
116 | };
117 |  
118 | 119 |
120 |
121 | 126 | 127 | 128 | 133 | 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /coverage/lcov-report/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Code coverage report for All files 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 |
21 |
22 |

All files

23 |
24 | 25 |
26 | 100% 27 | Statements 28 | 58/58 29 |
30 | 31 | 32 |
33 | 100% 34 | Branches 35 | 16/16 36 |
37 | 38 | 39 |
40 | 100% 41 | Functions 42 | 11/11 43 |
44 | 45 | 46 |
47 | 100% 48 | Lines 49 | 58/58 50 |
51 | 52 | 53 |
54 |

55 | Press n or j to go to the next uncovered block, b, p or k for the previous block. 56 |

57 |
58 |
59 |
60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 |
FileStatementsBranchesFunctionsLines
form_validator.js 78 |
79 |
100%5/5100%4/4100%3/3100%5/5
jsonp_helper.js 93 |
94 |
100%9/9100%0/0100%1/1100%9/9
photo_model.js 108 |
109 |
100%12/12100%0/0100%3/3100%12/12
route.js 123 |
124 |
100%17/17100%10/10100%4/4100%17/17
server.js 138 |
139 |
100%15/15100%2/2100%0/0100%15/15
152 |
153 |
154 |
155 | 160 | 161 | 162 | 167 | 168 | 169 | 170 | 171 | -------------------------------------------------------------------------------- /coverage/lcov-report/jsonp_helper.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Code coverage report for jsonp_helper.js 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 |
21 |
22 |

All files jsonp_helper.js

23 |
24 | 25 |
26 | 100% 27 | Statements 28 | 9/9 29 |
30 | 31 | 32 |
33 | 100% 34 | Branches 35 | 0/0 36 |
37 | 38 | 39 |
40 | 100% 41 | Functions 42 | 1/1 43 |
44 | 45 | 46 |
47 | 100% 48 | Lines 49 | 9/9 50 |
51 | 52 | 53 |
54 |

55 | Press n or j to go to the next uncovered block, b, p or k for the previous block. 56 |

57 |
58 |
59 |

 60 | 
1 61 | 2 62 | 3 63 | 4 64 | 5 65 | 6 66 | 7 67 | 8 68 | 9 69 | 10 70 | 11 71 | 12 72 | 13 73 | 14 74 | 15 75 | 16 76 | 17 77 | 18 78 | 19 79 | 20  80 | 5x 81 | 5x 82 | 5x 83 | 5x 84 |   85 |   86 | 5x 87 |   88 | 5x 89 |   90 | 2x 91 | 2x 92 |   93 |   94 |   95 | 4x 96 |   97 |   98 |  
function parseJSONP(jsonpData) {
 99 |   try {
100 |     const startPos = jsonpData.indexOf('({');
101 |     const endPos = jsonpData.lastIndexOf('})');
102 |     let jsonString = jsonpData.substring(startPos + 1, endPos + 1);
103 |  
104 |     // remove escaped single quotes since they are not valid json
105 |     jsonString = jsonString.replace(/\\'/g, "'");
106 |  
107 |     return JSON.parse(jsonString);
108 |   } catch (e) {
109 |     const error = new Error(`Failed to convert jsonp to json. ${e.message}`);
110 |     throw error;
111 |   }
112 | }
113 |  
114 | module.exports = {
115 |   parseJSONP
116 | };
117 |  
118 | 119 |
120 |
121 | 126 | 127 | 128 | 133 | 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /coverage/lcov-report/photo_model.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Code coverage report for photo_model.js 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 |
21 |
22 |

All files photo_model.js

23 |
24 | 25 |
26 | 100% 27 | Statements 28 | 12/12 29 |
30 | 31 | 32 |
33 | 100% 34 | Branches 35 | 0/0 36 |
37 | 38 | 39 |
40 | 100% 41 | Functions 42 | 3/3 43 |
44 | 45 | 46 |
47 | 100% 48 | Lines 49 | 12/12 50 |
51 | 52 | 53 |
54 |

55 | Press n or j to go to the next uncovered block, b, p or k for the previous block. 56 |

57 |
58 |
59 |

 60 | 
1 61 | 2 62 | 3 63 | 4 64 | 5 65 | 6 66 | 7 67 | 8 68 | 9 69 | 10 70 | 11 71 | 12 72 | 13 73 | 14 74 | 15 75 | 16 76 | 17 77 | 18 78 | 19 79 | 20 80 | 21 81 | 22 82 | 23 83 | 24 84 | 25 85 | 26 86 | 27 87 | 28 88 | 29 89 | 303x 90 | 3x 91 | 3x 92 |   93 |   94 | 3x 95 |   96 | 3x 97 |   98 |   99 |   100 |   101 |   102 |   103 | 3x 104 | 2x 105 |   106 | 1x 107 | 2x 108 | 2x 109 |   110 |   111 | 1x 112 |   113 |   114 |   115 | 3x 116 |   117 |   118 |  
const got = require('got');
119 | const querystring = require('querystring');
120 | const jsonpHelper = require('./jsonp_helper');
121 |  
122 | function getFlickrPhotos(tags, tagmode) {
123 |   const qs = querystring.stringify({ tags, tagmode, format: 'json' });
124 |  
125 |   const options = {
126 |     protocol: 'https:',
127 |     hostname: 'api.flickr.com',
128 |     path: `/services/feeds/photos_public.gne?${qs}`,
129 |     timeout: 10000
130 |   };
131 |  
132 |   return got(options).then(response => {
133 |     const photoFeed = jsonpHelper.parseJSONP(response.body);
134 |  
135 |     photoFeed.items.forEach(photo => {
136 |       photo.media.t = photo.media.m.split('m.jpg')[0] + 't.jpg';
137 |       photo.media.b = photo.media.m.split('m.jpg')[0] + 'b.jpg';
138 |     });
139 |  
140 |     return photoFeed.items;
141 |   });
142 | }
143 |  
144 | module.exports = {
145 |   getFlickrPhotos
146 | };
147 |  
148 | 149 |
150 |
151 | 156 | 157 | 158 | 163 | 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /coverage/lcov-report/prettify.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} 2 | -------------------------------------------------------------------------------- /coverage/lcov-report/prettify.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); 3 | -------------------------------------------------------------------------------- /coverage/lcov-report/route.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Code coverage report for route.js 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 |
21 |
22 |

All files route.js

23 |
24 | 25 |
26 | 100% 27 | Statements 28 | 17/17 29 |
30 | 31 | 32 |
33 | 100% 34 | Branches 35 | 10/10 36 |
37 | 38 | 39 |
40 | 100% 41 | Functions 42 | 4/4 43 |
44 | 45 | 46 |
47 | 100% 48 | Lines 49 | 17/17 50 |
51 | 52 | 53 |
54 |

55 | Press n or j to go to the next uncovered block, b, p or k for the previous block. 56 |

57 |
58 |
59 |

 60 | 
1 61 | 2 62 | 3 63 | 4 64 | 5 65 | 6 66 | 7 67 | 8 68 | 9 69 | 10 70 | 11 71 | 12 72 | 13 73 | 14 74 | 15 75 | 16 76 | 17 77 | 18 78 | 19 79 | 20 80 | 21 81 | 22 82 | 23 83 | 24 84 | 25 85 | 26 86 | 27 87 | 28 88 | 29 89 | 30 90 | 31 91 | 32 92 | 33 93 | 34 94 | 35 95 | 36 96 | 37 97 | 38 98 | 39 99 | 40 100 | 41 101 | 42 102 | 431x 103 | 1x 104 |   105 |   106 | 1x 107 | 4x 108 | 4x 109 |   110 | 4x 111 |   112 |   113 |   114 |   115 |   116 |   117 |   118 |   119 | 4x 120 | 1x 121 |   122 |   123 |   124 | 3x 125 | 1x 126 | 1x 127 |   128 |   129 |   130 | 2x 131 |   132 |   133 | 1x 134 | 1x 135 | 1x 136 |   137 |   138 | 1x 139 |   140 |   141 |   142 |   143 | 1x 144 |  
const formValidator = require('./form_validator');
145 | const photoModel = require('./photo_model');
146 |  
147 | function route(app) {
148 |   app.get('/', (req, res) => {
149 |     const tags = req.query.tags;
150 |     const tagmode = req.query.tagmode;
151 |  
152 |     const ejsLocalVariables = {
153 |       tagsParameter: tags || '',
154 |       tagmodeParameter: tagmode || '',
155 |       photos: [],
156 |       searchResults: false,
157 |       invalidParameters: false
158 |     };
159 |  
160 |     // if no input params are passed in then render the view with out querying the api
161 |     if (!tags && !tagmode) {
162 |       return res.render('index', ejsLocalVariables);
163 |     }
164 |  
165 |     // validate query parameters
166 |     if (!formValidator.hasValidFlickrAPIParams(tags, tagmode)) {
167 |       ejsLocalVariables.invalidParameters = true;
168 |       return res.render('index', ejsLocalVariables);
169 |     }
170 |  
171 |     // get photos from flickr public feed api
172 |     return photoModel
173 |       .getFlickrPhotos(tags, tagmode)
174 |       .then(photos => {
175 |         ejsLocalVariables.photos = photos;
176 |         ejsLocalVariables.searchResults = true;
177 |         return res.render('index', ejsLocalVariables);
178 |       })
179 |       .catch(error => {
180 |         return res.status(500).send({ error });
181 |       });
182 |   });
183 | }
184 |  
185 | module.exports = route;
186 |  
187 | 188 |
189 |
190 | 195 | 196 | 197 | 202 | 203 | 204 | 205 | 206 | -------------------------------------------------------------------------------- /coverage/lcov-report/server.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Code coverage report for server.js 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 | 20 |
21 |
22 |

All files server.js

23 |
24 | 25 |
26 | 100% 27 | Statements 28 | 15/15 29 |
30 | 31 | 32 |
33 | 100% 34 | Branches 35 | 2/2 36 |
37 | 38 | 39 |
40 | 100% 41 | Functions 42 | 0/0 43 |
44 | 45 | 46 |
47 | 100% 48 | Lines 49 | 15/15 50 |
51 | 52 | 53 |
54 |

55 | Press n or j to go to the next uncovered block, b, p or k for the previous block. 56 |

57 |
58 |
59 |

 60 | 
1 61 | 2 62 | 3 63 | 4 64 | 5 65 | 6 66 | 7 67 | 8 68 | 9 69 | 10 70 | 11 71 | 12 72 | 13 73 | 14 74 | 15 75 | 16 76 | 17 77 | 18 78 | 19 79 | 20 80 | 21 81 | 22 82 | 23 83 | 24 84 | 25 85 | 261x 86 | 1x 87 | 1x 88 |   89 | 1x 90 |   91 |   92 | 1x 93 | 1x 94 | 1x 95 |   96 |   97 | 1x 98 | 1x 99 | 1x 100 |   101 |   102 | 1x 103 |   104 |   105 | 1x 106 | 1x 107 | 1x 108 |   109 | 1x 110 |  
const express = require('express');
111 | const favicon = require('serve-favicon');
112 | const path = require('path');
113 |  
114 | const app = express();
115 |  
116 | // public assets
117 | app.use(express.static(path.join(__dirname, 'public')));
118 | app.use(favicon(path.join(__dirname, 'public/images', 'favicon.ico')));
119 | app.use('/coverage', express.static(path.join(__dirname, '..', 'coverage')));
120 |  
121 | // ejs for view templates
122 | app.engine('.html', require('ejs').__express);
123 | app.set('views', path.join(__dirname, 'views'));
124 | app.set('view engine', 'html');
125 |  
126 | // load route
127 | require('./route')(app);
128 |  
129 | // server
130 | const port = process.env.PORT || 3000;
131 | app.server = app.listen(port);
132 | console.log(`listening on port ${port}`);
133 |  
134 | module.exports = app;
135 |  
136 | 137 |
138 |
139 | 144 | 145 | 146 | 151 | 152 | 153 | 154 | 155 | -------------------------------------------------------------------------------- /coverage/lcov-report/sort-arrow-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gregjopa/express-app-testing-demo/c68df7b899b23f74d8dd8a0862fd4e512ec0f6f5/coverage/lcov-report/sort-arrow-sprite.png -------------------------------------------------------------------------------- /coverage/lcov-report/sorter.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | var addSorting = (function() { 3 | 'use strict'; 4 | var cols, 5 | currentSort = { 6 | index: 0, 7 | desc: false 8 | }; 9 | 10 | // returns the summary table element 11 | function getTable() { 12 | return document.querySelector('.coverage-summary'); 13 | } 14 | // returns the thead element of the summary table 15 | function getTableHeader() { 16 | return getTable().querySelector('thead tr'); 17 | } 18 | // returns the tbody element of the summary table 19 | function getTableBody() { 20 | return getTable().querySelector('tbody'); 21 | } 22 | // returns the th element for nth column 23 | function getNthColumn(n) { 24 | return getTableHeader().querySelectorAll('th')[n]; 25 | } 26 | 27 | // loads all columns 28 | function loadColumns() { 29 | var colNodes = getTableHeader().querySelectorAll('th'), 30 | colNode, 31 | cols = [], 32 | col, 33 | i; 34 | 35 | for (i = 0; i < colNodes.length; i += 1) { 36 | colNode = colNodes[i]; 37 | col = { 38 | key: colNode.getAttribute('data-col'), 39 | sortable: !colNode.getAttribute('data-nosort'), 40 | type: colNode.getAttribute('data-type') || 'string' 41 | }; 42 | cols.push(col); 43 | if (col.sortable) { 44 | col.defaultDescSort = col.type === 'number'; 45 | colNode.innerHTML = 46 | colNode.innerHTML + ''; 47 | } 48 | } 49 | return cols; 50 | } 51 | // attaches a data attribute to every tr element with an object 52 | // of data values keyed by column name 53 | function loadRowData(tableRow) { 54 | var tableCols = tableRow.querySelectorAll('td'), 55 | colNode, 56 | col, 57 | data = {}, 58 | i, 59 | val; 60 | for (i = 0; i < tableCols.length; i += 1) { 61 | colNode = tableCols[i]; 62 | col = cols[i]; 63 | val = colNode.getAttribute('data-value'); 64 | if (col.type === 'number') { 65 | val = Number(val); 66 | } 67 | data[col.key] = val; 68 | } 69 | return data; 70 | } 71 | // loads all row data 72 | function loadData() { 73 | var rows = getTableBody().querySelectorAll('tr'), 74 | i; 75 | 76 | for (i = 0; i < rows.length; i += 1) { 77 | rows[i].data = loadRowData(rows[i]); 78 | } 79 | } 80 | // sorts the table using the data for the ith column 81 | function sortByIndex(index, desc) { 82 | var key = cols[index].key, 83 | sorter = function(a, b) { 84 | a = a.data[key]; 85 | b = b.data[key]; 86 | return a < b ? -1 : a > b ? 1 : 0; 87 | }, 88 | finalSorter = sorter, 89 | tableBody = document.querySelector('.coverage-summary tbody'), 90 | rowNodes = tableBody.querySelectorAll('tr'), 91 | rows = [], 92 | i; 93 | 94 | if (desc) { 95 | finalSorter = function(a, b) { 96 | return -1 * sorter(a, b); 97 | }; 98 | } 99 | 100 | for (i = 0; i < rowNodes.length; i += 1) { 101 | rows.push(rowNodes[i]); 102 | tableBody.removeChild(rowNodes[i]); 103 | } 104 | 105 | rows.sort(finalSorter); 106 | 107 | for (i = 0; i < rows.length; i += 1) { 108 | tableBody.appendChild(rows[i]); 109 | } 110 | } 111 | // removes sort indicators for current column being sorted 112 | function removeSortIndicators() { 113 | var col = getNthColumn(currentSort.index), 114 | cls = col.className; 115 | 116 | cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); 117 | col.className = cls; 118 | } 119 | // adds sort indicators for current column being sorted 120 | function addSortIndicators() { 121 | getNthColumn(currentSort.index).className += currentSort.desc 122 | ? ' sorted-desc' 123 | : ' sorted'; 124 | } 125 | // adds event listeners for all sorter widgets 126 | function enableUI() { 127 | var i, 128 | el, 129 | ithSorter = function ithSorter(i) { 130 | var col = cols[i]; 131 | 132 | return function() { 133 | var desc = col.defaultDescSort; 134 | 135 | if (currentSort.index === i) { 136 | desc = !currentSort.desc; 137 | } 138 | sortByIndex(i, desc); 139 | removeSortIndicators(); 140 | currentSort.index = i; 141 | currentSort.desc = desc; 142 | addSortIndicators(); 143 | }; 144 | }; 145 | for (i = 0; i < cols.length; i += 1) { 146 | if (cols[i].sortable) { 147 | // add the click event handler on the th so users 148 | // dont have to click on those tiny arrows 149 | el = getNthColumn(i).querySelector('.sorter').parentElement; 150 | if (el.addEventListener) { 151 | el.addEventListener('click', ithSorter(i)); 152 | } else { 153 | el.attachEvent('onclick', ithSorter(i)); 154 | } 155 | } 156 | } 157 | } 158 | // adds sorting functionality to the UI 159 | return function() { 160 | if (!getTable()) { 161 | return; 162 | } 163 | cols = loadColumns(); 164 | loadData(); 165 | addSortIndicators(); 166 | enableUI(); 167 | }; 168 | })(); 169 | 170 | window.addEventListener('load', addSorting); 171 | -------------------------------------------------------------------------------- /coverage/lcov.info: -------------------------------------------------------------------------------- 1 | TN: 2 | SF:app/form_validator.js 3 | FN:1,isValidCommaDelimitedList 4 | FN:7,isValidTagmode 5 | FN:11,hasValidFlickrAPIParams 6 | FNF:3 7 | FNH:3 8 | FNDA:10,isValidCommaDelimitedList 9 | FNDA:7,isValidTagmode 10 | FNDA:6,hasValidFlickrAPIParams 11 | DA:3,10 12 | DA:4,10 13 | DA:8,7 14 | DA:12,6 15 | DA:15,2 16 | LF:5 17 | LH:5 18 | BRDA:8,0,0,7 19 | BRDA:8,0,1,3 20 | BRDA:12,1,0,6 21 | BRDA:12,1,1,4 22 | BRF:4 23 | BRH:4 24 | end_of_record 25 | TN: 26 | SF:app/jsonp_helper.js 27 | FN:1,parseJSONP 28 | FNF:1 29 | FNH:1 30 | FNDA:5,parseJSONP 31 | DA:2,5 32 | DA:3,5 33 | DA:4,5 34 | DA:5,5 35 | DA:8,5 36 | DA:10,5 37 | DA:12,2 38 | DA:13,2 39 | DA:17,4 40 | LF:9 41 | LH:9 42 | BRF:0 43 | BRH:0 44 | end_of_record 45 | TN: 46 | SF:app/photo_model.js 47 | FN:5,getFlickrPhotos 48 | FN:15,(anonymous_1) 49 | FN:18,(anonymous_2) 50 | FNF:3 51 | FNH:3 52 | FNDA:3,getFlickrPhotos 53 | FNDA:2,(anonymous_1) 54 | FNDA:2,(anonymous_2) 55 | DA:1,3 56 | DA:2,3 57 | DA:3,3 58 | DA:6,3 59 | DA:8,3 60 | DA:15,3 61 | DA:16,2 62 | DA:18,1 63 | DA:19,2 64 | DA:20,2 65 | DA:23,1 66 | DA:27,3 67 | LF:12 68 | LH:12 69 | BRF:0 70 | BRH:0 71 | end_of_record 72 | TN: 73 | SF:app/route.js 74 | FN:4,route 75 | FN:5,(anonymous_1) 76 | FN:31,(anonymous_2) 77 | FN:36,(anonymous_3) 78 | FNF:4 79 | FNH:4 80 | FNDA:1,route 81 | FNDA:4,(anonymous_1) 82 | FNDA:1,(anonymous_2) 83 | FNDA:1,(anonymous_3) 84 | DA:1,1 85 | DA:2,1 86 | DA:5,1 87 | DA:6,4 88 | DA:7,4 89 | DA:9,4 90 | DA:18,4 91 | DA:19,1 92 | DA:23,3 93 | DA:24,1 94 | DA:25,1 95 | DA:29,2 96 | DA:32,1 97 | DA:33,1 98 | DA:34,1 99 | DA:37,1 100 | DA:42,1 101 | LF:17 102 | LH:17 103 | BRDA:10,0,0,4 104 | BRDA:10,0,1,1 105 | BRDA:11,1,0,4 106 | BRDA:11,1,1,1 107 | BRDA:18,2,0,1 108 | BRDA:18,2,1,3 109 | BRDA:18,3,0,4 110 | BRDA:18,3,1,1 111 | BRDA:23,4,0,1 112 | BRDA:23,4,1,2 113 | BRF:10 114 | BRH:10 115 | end_of_record 116 | TN: 117 | SF:app/server.js 118 | FNF:0 119 | FNH:0 120 | DA:1,1 121 | DA:2,1 122 | DA:3,1 123 | DA:5,1 124 | DA:8,1 125 | DA:9,1 126 | DA:10,1 127 | DA:13,1 128 | DA:14,1 129 | DA:15,1 130 | DA:18,1 131 | DA:21,1 132 | DA:22,1 133 | DA:23,1 134 | DA:25,1 135 | LF:15 136 | LH:15 137 | BRDA:21,0,0,1 138 | BRDA:21,0,1,1 139 | BRF:2 140 | BRH:2 141 | end_of_record 142 | -------------------------------------------------------------------------------- /e2e_tests/flickr_public_feed_api.test.js: -------------------------------------------------------------------------------- 1 | const got = require('got'); 2 | const querystring = require('querystring'); 3 | const jsonpHelper = require('../app/jsonp_helper'); 4 | 5 | class API { 6 | constructor({ tags = '', tagmode = '', format = 'json' }) { 7 | const qs = querystring.stringify({ tags, tagmode, format }); 8 | this.hostname = 'api.flickr.com'; 9 | this.path = `/services/feeds/photos_public.gne?${qs}`; 10 | this.protocol = 'https:'; 11 | } 12 | } 13 | 14 | describe('flickr public feed api', () => { 15 | test('should return expected json format', () => { 16 | const apiTest = new API({ 17 | tags: 'california', 18 | tagmode: 'all' 19 | }); 20 | 21 | return got(apiTest).then(response => { 22 | expect(response.statusCode).toBe(200); 23 | 24 | const photoFeed = jsonpHelper.parseJSONP(response.body); 25 | expect(photoFeed).toHaveProperty('items'); 26 | 27 | const photos = photoFeed.items; 28 | expect(photos).toBeInstanceOf(Array); 29 | 30 | photos.forEach(function(photo) { 31 | expect(Object.keys(photo)).toEqual( 32 | expect.arrayContaining([ 33 | 'title', 34 | 'link', 35 | 'media', 36 | 'date_taken', 37 | 'description', 38 | 'published', 39 | 'author', 40 | 'author_id', 41 | 'tags' 42 | ]) 43 | ); 44 | }); 45 | }); 46 | }); 47 | 48 | test('should return many photos', () => { 49 | const apiTest = new API({ 50 | tags: 'california, beach, blue', 51 | tagmode: 'any' 52 | }); 53 | 54 | return got(apiTest).then(response => { 55 | expect(response.statusCode).toBe(200); 56 | 57 | const photoFeed = jsonpHelper.parseJSONP(response.body); 58 | expect(photoFeed).toHaveProperty('items'); 59 | 60 | const photos = photoFeed.items; 61 | expect(photos.length).toBeGreaterThan(0); 62 | }); 63 | }); 64 | 65 | test('should return zero photos', () => { 66 | // these tags should return zero results 67 | const apiTest = new API({ 68 | tags: 'bad,parameters,abc,111,999', 69 | tagmode: 'all' 70 | }); 71 | 72 | return got(apiTest).then(response => { 73 | expect(response.statusCode).toBe(200); 74 | 75 | const photoFeed = jsonpHelper.parseJSONP(response.body); 76 | expect(photoFeed).toHaveProperty('items'); 77 | 78 | const photos = photoFeed.items; 79 | expect(photos.length).toBe(0); 80 | }); 81 | }); 82 | }); 83 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "express-app-testing-demo", 3 | "description": "a simple express app for demonstrating testing and code coverage", 4 | "version": "1.0.0", 5 | "engines": { 6 | "node": ">=12" 7 | }, 8 | "private": true, 9 | "main": "app/server.js", 10 | "scripts": { 11 | "start": "nodemon app/server.js", 12 | "test": "npm run lint && npm run jest", 13 | "test:e2e": "jest --runInBand e2e_tests/*.test.js", 14 | "jest": "jest --coverage app/__tests__/*.test.js", 15 | "lint": "eslint app/*.js e2e_tests/*.js", 16 | "prettier": "prettier --write app/*.js app/__{tests,mocks}__/*.js e2e_tests/*.js" 17 | }, 18 | "dependencies": { 19 | "ejs": "~3.1.3", 20 | "express": "~4.17.1", 21 | "got": "^11.1.4", 22 | "serve-favicon": "^2.5.0" 23 | }, 24 | "devDependencies": { 25 | "eslint": "^7.0.0", 26 | "jest": "^26.0.1", 27 | "nodemon": "^2.0.4", 28 | "prettier": "^2.0.5", 29 | "supertest": "~4.0.2" 30 | }, 31 | "repository": { 32 | "type": "git", 33 | "url": "https://github.com/gregjopa/express-app-testing-demo" 34 | }, 35 | "jest": { 36 | "testEnvironment": "node", 37 | "verbose": true 38 | }, 39 | "prettier": { 40 | "singleQuote": true 41 | } 42 | } 43 | --------------------------------------------------------------------------------