+ {{this.model.errors.firstObject}} +
diff --git a/test-projects/01-basic-app/app/pods/crud-demo/controller.js b/test-projects/01-basic-app/app/pods/crud-demo/controller.js new file mode 100644 index 000000000..4acd8334a --- /dev/null +++ b/test-projects/01-basic-app/app/pods/crud-demo/controller.js @@ -0,0 +1,35 @@ +import Controller from '@ember/controller'; +import { inject as service } from '@ember/service'; +import { action } from '@ember/object'; +import { tracked } from '@glimmer/tracking'; + +export default class extends Controller { + @service store; + + @tracked newName; + + @action createUser(event) { + event.preventDefault(); + + let name = this.newName; + + this.store + .createRecord('user', { name }) + .save() + .then(() => { + this.newName = ''; + }); + } + + @action updateUser(user, event) { + event.preventDefault(); + + user.save(); + } + + @action deleteUser(user, event) { + event.preventDefault(); + + user.destroyRecord(); + } +} diff --git a/test-projects/01-basic-app/app/pods/crud-demo/route.js b/test-projects/01-basic-app/app/pods/crud-demo/route.js new file mode 100644 index 000000000..e4f198d40 --- /dev/null +++ b/test-projects/01-basic-app/app/pods/crud-demo/route.js @@ -0,0 +1,10 @@ +import Route from '@ember/routing/route'; +import { inject as service } from '@ember/service'; + +export default class extends Route { + @service store; + + model() { + return this.store.findAll('user'); + } +} diff --git a/test-projects/01-basic-app/app/pods/crud-demo/template.hbs b/test-projects/01-basic-app/app/pods/crud-demo/template.hbs new file mode 100644 index 000000000..d074dca68 --- /dev/null +++ b/test-projects/01-basic-app/app/pods/crud-demo/template.hbs @@ -0,0 +1,48 @@ +{{#if this.error}} + ++ There was an error: {{this.error}} +
+ +{{else}} + + {{#each this.model as |user|}} ++ Environment: + + {{this.environment}} + +
+ ++ Mirage modules in project: + + {{this.mirageModules.length}} + +
+ ++ Other modules in project: + + {{this.otherIncludedModules.length}} + +
diff --git a/test-projects/01-basic-app/app/router.js b/test-projects/01-basic-app/app/router.js new file mode 100644 index 000000000..797295e13 --- /dev/null +++ b/test-projects/01-basic-app/app/router.js @@ -0,0 +1,12 @@ +import EmberRouter from '@ember/routing/router'; +import config from 'basic-app/config/environment'; + +export default class Router extends EmberRouter { + location = config.locationType; + rootURL = config.rootURL; +} + +Router.map(function () { + this.route('module-count'); + this.route('crud-demo'); +}); diff --git a/test-projects/01-basic-app/app/routes/.gitkeep b/test-projects/01-basic-app/app/routes/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/test-projects/01-basic-app/app/serializers/application.js b/test-projects/01-basic-app/app/serializers/application.js new file mode 100644 index 000000000..33d31a206 --- /dev/null +++ b/test-projects/01-basic-app/app/serializers/application.js @@ -0,0 +1,3 @@ +import JSONAPISerializer from '@ember-data/serializer/json-api'; + +export default class extends JSONAPISerializer {} diff --git a/test-projects/01-basic-app/app/styles/app.css b/test-projects/01-basic-app/app/styles/app.css new file mode 100644 index 000000000..e69de29bb diff --git a/test-projects/01-basic-app/app/templates/application.hbs b/test-projects/01-basic-app/app/templates/application.hbs new file mode 100644 index 000000000..aa16a3ead --- /dev/null +++ b/test-projects/01-basic-app/app/templates/application.hbs @@ -0,0 +1,22 @@ ++ Environment: + + {{this.environment}} + +
+ ++ Mirage modules in project: + + {{this.mirageModules.length}} + +
+ ++ Other modules in project: + + {{this.otherIncludedModules.length}} + +
diff --git a/test-projects/01-basic-app/config/ember-cli-update.json b/test-projects/01-basic-app/config/ember-cli-update.json new file mode 100644 index 000000000..4d3d25b5a --- /dev/null +++ b/test-projects/01-basic-app/config/ember-cli-update.json @@ -0,0 +1,21 @@ +{ + "schemaVersion": "1.0.0", + "packages": [ + { + "name": "ember-cli", + "version": "3.28.4", + "blueprints": [ + { + "name": "app", + "outputRepo": "https://github.com/ember-cli/ember-new-output", + "codemodsSource": "ember-app-codemods-manifest@1", + "isBaseBlueprint": true, + "options": [ + "--yarn", + "--no-welcome" + ] + } + ] + } + ] +} diff --git a/test-projects/01-basic-app/config/environment.js b/test-projects/01-basic-app/config/environment.js new file mode 100644 index 000000000..1af33a9ba --- /dev/null +++ b/test-projects/01-basic-app/config/environment.js @@ -0,0 +1,58 @@ +'use strict'; + +module.exports = function (environment) { + let ENV = { + modulePrefix: 'basic-app', + podModulePrefix: 'basic-app/pods', + environment, + rootURL: '/', + locationType: 'auto', + EmberENV: { + FEATURES: { + // Here you can enable experimental features on an ember canary build + // e.g. EMBER_NATIVE_DECORATOR_SUPPORT: true + }, + EXTEND_PROTOTYPES: { + // Prevent Ember Data from overriding Date.parse. + Date: false, + }, + }, + + APP: { + // Here you can pass flags/options to your application instance + // when it is created + }, + }; + + if (process.env.MIRAGE_ENABLED) { + ENV['ember-cli-mirage'] = { + enabled: true, + }; + } + + if (environment === 'development') { + // ENV.APP.LOG_RESOLVER = true; + // ENV.APP.LOG_ACTIVE_GENERATION = true; + // ENV.APP.LOG_TRANSITIONS = true; + // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; + // ENV.APP.LOG_VIEW_LOOKUPS = true; + } + + if (environment === 'test') { + // Testem prefers this... + ENV.locationType = 'none'; + + // keep test console output quieter + ENV.APP.LOG_ACTIVE_GENERATION = false; + ENV.APP.LOG_VIEW_LOOKUPS = false; + + ENV.APP.rootElement = '#ember-testing'; + ENV.APP.autoboot = false; + } + + if (environment === 'production') { + // here you can enable a production-specific feature + } + + return ENV; +}; diff --git a/test-projects/01-basic-app/config/optional-features.json b/test-projects/01-basic-app/config/optional-features.json new file mode 100644 index 000000000..b26286e2e --- /dev/null +++ b/test-projects/01-basic-app/config/optional-features.json @@ -0,0 +1,6 @@ +{ + "application-template-wrapper": false, + "default-async-observers": true, + "jquery-integration": false, + "template-only-glimmer-components": true +} diff --git a/test-projects/01-basic-app/config/targets.js b/test-projects/01-basic-app/config/targets.js new file mode 100644 index 000000000..0b433b73c --- /dev/null +++ b/test-projects/01-basic-app/config/targets.js @@ -0,0 +1,27 @@ +'use strict'; + +const browsers = [ + 'last 1 Chrome versions', + 'last 1 Firefox versions', + 'last 1 Safari versions', +]; + +// Ember's browser support policy is changing, and IE11 support will end in +// v4.0 onwards. +// +// See https://deprecations.emberjs.com/v3.x#toc_3-0-browser-support-policy +// +// If you need IE11 support on a version of Ember that still offers support +// for it, uncomment the code block below. +// +// const isCI = Boolean(process.env.CI); +// const isProduction = process.env.EMBER_ENV === 'production'; +// +// if (isCI || isProduction) { +// browsers.push('ie 11'); +// } + +module.exports = { + browsers, + node: 'current', +}; diff --git a/test-projects/01-basic-app/ember-cli-build.js b/test-projects/01-basic-app/ember-cli-build.js new file mode 100644 index 000000000..633f74278 --- /dev/null +++ b/test-projects/01-basic-app/ember-cli-build.js @@ -0,0 +1,26 @@ +'use strict'; + +const EmberApp = require('ember-cli/lib/broccoli/ember-app'); + +module.exports = function (defaults) { + let app = new EmberApp(defaults, { + autoImport: { + exclude: ['qunit'], + }, + }); + + // Use `app.import` to add additional libraries to the generated + // output files. + // + // If you need to use different assets in different + // environments, specify an object as the first parameter. That + // object's keys should be the environment name and the values + // should be the asset to use in that environment. + // + // If the library that you are including contains AMD or ES6 + // modules that you would like to import into your application + // please specify an object with the list of modules as keys + // along with the exports of each module as its value. + + return app.toTree(); +}; diff --git a/test-projects/01-basic-app/fastboot-tests/included-files-test.js b/test-projects/01-basic-app/fastboot-tests/included-files-test.js new file mode 100644 index 000000000..ae6d5cd34 --- /dev/null +++ b/test-projects/01-basic-app/fastboot-tests/included-files-test.js @@ -0,0 +1,141 @@ +const FastBoot = require('fastboot'); +const { execFileSync } = require('child_process'); +const { module: qModule, test } = require('qunit'); +const jsdom = require('jsdom'); +const { JSDOM } = jsdom; + +const findTextFromHtml = (html, selector) => { + let document = new JSDOM(html).window.document; + return document.querySelector(selector).textContent.trim(); +}; + +qModule('basic-app | fastboot | included files', function () { + test('it includes all modules in development by default', async function (assert) { + execFileSync('node', [require.resolve('ember-cli/bin/ember'), 'build']); + let fastboot = new FastBoot({ + distPath: 'dist', + resilient: false, + }); + + let page = await fastboot.visit('/module-count', { + request: { + url: '/module-count', + protocol: 'https:', + headers: {}, + }, + response: {}, + }); + let html = await page.html(); + + assert.equal( + findTextFromHtml(html, '[data-test-id="environment"]'), + 'development' + ); + assert.ok( + +findTextFromHtml(html, '[data-test-id="mirage-module-count"]') > 1 + ); + assert.ok( + +findTextFromHtml(html, '[data-test-id="other-module-count"]') > 1 + ); + }); + + test('it includes all modules in test by default', async function (assert) { + execFileSync('node', [ + require.resolve('ember-cli/bin/ember'), + 'build', + '--environment=test', + ]); + let fastboot = new FastBoot({ + distPath: 'dist', + resilient: false, + }); + + let page = await fastboot.visit('/module-count', { + request: { + url: '/module-count', + protocol: 'https:', + headers: {}, + }, + response: {}, + }); + let html = await page.html(); + + assert.equal( + findTextFromHtml(html, '[data-test-id="environment"]'), + 'test' + ); + assert.ok( + +findTextFromHtml(html, '[data-test-id="mirage-module-count"]') > 1 + ); + assert.ok( + +findTextFromHtml(html, '[data-test-id="other-module-count"]') > 1 + ); + }); + + test('it only includes an initializer in production by default', async function (assert) { + execFileSync('node', [ + require.resolve('ember-cli/bin/ember'), + 'build', + '-prod', + ]); + let fastboot = new FastBoot({ + distPath: 'dist', + resilient: false, + }); + let page = await fastboot.visit('/module-count', { + request: { + url: '/module-count', + protocol: 'https:', + headers: {}, + }, + response: {}, + }); + let html = await page.html(); + + assert.equal( + findTextFromHtml(html, '[data-test-id="environment"]'), + 'production' + ); + assert.equal( + findTextFromHtml(html, '[data-test-id="mirage-module-count"]'), + '0' + ); + assert.equal( + findTextFromHtml(html, '[data-test-id="other-module-count"]'), + '1' + ); + }); + + test('all files can be included in production by explicitly setting enabled to true', async function (assert) { + process.env.MIRAGE_ENABLED = 'true'; + execFileSync('node', [ + require.resolve('ember-cli/bin/ember'), + 'build', + '-prod', + ]); + let fastboot = new FastBoot({ + distPath: 'dist', + resilient: false, + }); + let page = await fastboot.visit('/module-count', { + request: { + url: '/module-count', + protocol: 'https:', + headers: {}, + }, + response: {}, + }); + let html = await page.html(); + + assert.equal( + findTextFromHtml(html, '[data-test-id="environment"]'), + 'production' + ); + assert.ok( + +findTextFromHtml(html, '[data-test-id="mirage-module-count"]') > 1 + ); + assert.ok( + +findTextFromHtml(html, '[data-test-id="other-module-count"]') > 1 + ); + }); +}); diff --git a/test-projects/01-basic-app/mirage/config.js b/test-projects/01-basic-app/mirage/config.js new file mode 100644 index 000000000..bb5285750 --- /dev/null +++ b/test-projects/01-basic-app/mirage/config.js @@ -0,0 +1,3 @@ +export default function () { + this.resource('user'); +} diff --git a/test-projects/01-basic-app/mirage/factories/nested/thing.js b/test-projects/01-basic-app/mirage/factories/nested/thing.js new file mode 100644 index 000000000..c2692a773 --- /dev/null +++ b/test-projects/01-basic-app/mirage/factories/nested/thing.js @@ -0,0 +1,5 @@ +import { Factory } from 'miragejs'; + +export default Factory.extend({ + name: 'nested factory works!', +}); diff --git a/test-projects/01-basic-app/mirage/factories/user.js b/test-projects/01-basic-app/mirage/factories/user.js new file mode 100644 index 000000000..797df9909 --- /dev/null +++ b/test-projects/01-basic-app/mirage/factories/user.js @@ -0,0 +1,8 @@ +import { Factory } from 'miragejs'; +import faker from 'faker'; + +export default Factory.extend({ + age() { + return faker.datatype.number({ min: 32, max: 32 }); + }, +}); diff --git a/test-projects/01-basic-app/mirage/fixtures/countries.js b/test-projects/01-basic-app/mirage/fixtures/countries.js new file mode 100644 index 000000000..129fc618c --- /dev/null +++ b/test-projects/01-basic-app/mirage/fixtures/countries.js @@ -0,0 +1 @@ +export default [{ name: 'United State' }]; diff --git a/test-projects/01-basic-app/mirage/fixtures/nested/things.js b/test-projects/01-basic-app/mirage/fixtures/nested/things.js new file mode 100644 index 000000000..bfd4cb47d --- /dev/null +++ b/test-projects/01-basic-app/mirage/fixtures/nested/things.js @@ -0,0 +1 @@ +export default [{ fixtureField: 'nested fixture works!' }]; diff --git a/test-projects/01-basic-app/mirage/fixtures/users.js b/test-projects/01-basic-app/mirage/fixtures/users.js new file mode 100644 index 000000000..42dd95037 --- /dev/null +++ b/test-projects/01-basic-app/mirage/fixtures/users.js @@ -0,0 +1 @@ +export default [{ id: 1, name: 'Sam' }]; diff --git a/test-projects/01-basic-app/mirage/identity-managers/book.js b/test-projects/01-basic-app/mirage/identity-managers/book.js new file mode 100644 index 000000000..4ba1e894f --- /dev/null +++ b/test-projects/01-basic-app/mirage/identity-managers/book.js @@ -0,0 +1,59 @@ +export default class { + constructor() { + this.reset(); + } + + /** + * Returns an unique identifier. + * + * @method fetch + * @return {String} Unique identifier + * @public + */ + fetch() { + let alphabet = 'abcdefghijklmnopqrstuvwxyz'; + let id; + + if (this._nextId >= alphabet.length) { + throw new Error( + `IdentityManager used for testing only supports ${alphabet.length} ids.` + ); + } + id = alphabet[this._nextId % alphabet.length]; + this._ids[id] = true; + this._nextId = this._nextid + 1; + return id; + } + + /** + * Register an identifier. + * Must throw if identifier is already used. + * + * @method set + * @param {String|Number} id + * @public + */ + set(id) { + if (typeof this._ids[id] !== 'undefined') { + throw new Error(`Id {id} is already used.`); + } + + this._ids[id] = true; + + let int = parseInt(id, 16); + if (!isNaN(int) && int > this._nextid) { + this._nextId = int; + } + } + + /** + * Reset identity manager. + * + * @method reset + * @public + */ + reset() { + this._nextId = 0; + this._ids = {}; + } +} diff --git a/test-projects/01-basic-app/mirage/identity-managers/nested/thing.js b/test-projects/01-basic-app/mirage/identity-managers/nested/thing.js new file mode 100644 index 000000000..e7fc3b4e2 --- /dev/null +++ b/test-projects/01-basic-app/mirage/identity-managers/nested/thing.js @@ -0,0 +1,58 @@ +export default class { + constructor() { + this.reset(); + } + + /** + * Returns an unique identifier. + * + * @method fetch + * @return {String} Unique identifier + * @public + */ + fetch() { + let id; + + if (this._nextId >= 1) { + throw new Error( + `IdentityManager used for testing only supports single id.` + ); + } + id = 'nested identity manager works!'; + this._ids[id] = true; + this._nextId = this._nextid + 1; + return id; + } + + /** + * Register an identifier. + * Must throw if identifier is already used. + * + * @method set + * @param {String|Number} id + * @public + */ + set(id) { + if (typeof this._ids[id] !== 'undefined') { + throw new Error(`Id {id} is already used.`); + } + + this._ids[id] = true; + + let int = parseInt(id, 16); + if (!isNaN(int) && int > this._nextid) { + this._nextId = int; + } + } + + /** + * Reset identity manager. + * + * @method reset + * @public + */ + reset() { + this._nextId = 0; + this._ids = {}; + } +} diff --git a/test-projects/01-basic-app/mirage/models/nested/thing.js b/test-projects/01-basic-app/mirage/models/nested/thing.js new file mode 100644 index 000000000..db502f142 --- /dev/null +++ b/test-projects/01-basic-app/mirage/models/nested/thing.js @@ -0,0 +1,3 @@ +import { Model } from 'miragejs'; + +export default Model.extend({}); diff --git a/test-projects/01-basic-app/mirage/scenarios/default.js b/test-projects/01-basic-app/mirage/scenarios/default.js new file mode 100644 index 000000000..bc83f83ce --- /dev/null +++ b/test-projects/01-basic-app/mirage/scenarios/default.js @@ -0,0 +1,5 @@ +export default function (server) { + server.create('user', { name: 'Yehuda' }); + server.create('user', { name: 'Tom' }); + server.create('user', { name: 'Leah' }); +} diff --git a/test-projects/01-basic-app/mirage/serializers/application.js b/test-projects/01-basic-app/mirage/serializers/application.js new file mode 100644 index 000000000..6753a45f3 --- /dev/null +++ b/test-projects/01-basic-app/mirage/serializers/application.js @@ -0,0 +1,3 @@ +import { JSONAPISerializer } from 'miragejs'; + +export default JSONAPISerializer; diff --git a/test-projects/01-basic-app/mirage/serializers/nested/thing.js b/test-projects/01-basic-app/mirage/serializers/nested/thing.js new file mode 100644 index 000000000..103273872 --- /dev/null +++ b/test-projects/01-basic-app/mirage/serializers/nested/thing.js @@ -0,0 +1,12 @@ +import ApplicationSerizlizer from '../application'; + +export default ApplicationSerizlizer.extend({ + keyForAttribute(attr) { + const key = ApplicationSerizlizer.prototype.keyForAttribute.call( + this, + attr + ); + + return `nested_thing_${key}`; + }, +}); diff --git a/test-projects/01-basic-app/package.json b/test-projects/01-basic-app/package.json new file mode 100644 index 000000000..acc03f67e --- /dev/null +++ b/test-projects/01-basic-app/package.json @@ -0,0 +1,64 @@ +{ + "name": "basic-app", + "version": "0.0.0", + "private": true, + "description": "Small description for basic-app goes here", + "license": "MIT", + "author": "", + "directories": { + "doc": "doc", + "test": "tests" + }, + "repository": "", + "scripts": { + "build": "ember build --environment=production", + "start": "ember serve", + "test": "npm-run-all lint test:*", + "test:ember": "ember test --test-port=0", + "test:fastboot": "qunit fastboot-tests/**/*.js" + }, + "devDependencies": { + "@ember/jquery": "*", + "@ember/optional-features": "*", + "@ember/test-helpers": "*", + "@embroider/test-setup": "*", + "@glimmer/component": "*", + "@glimmer/tracking": "*", + "broccoli-asset-rev": "*", + "ember-auto-import": "*", + "ember-cli": "*", + "ember-cli-babel": "*", + "ember-cli-dependency-checker": "*", + "ember-cli-fastboot": "*", + "ember-cli-htmlbars": "*", + "ember-cli-inject-live-reload": "*", + "ember-cli-mirage": "*", + "ember-cli-sri": "*", + "ember-cli-terser": "*", + "ember-data": "*", + "ember-export-application-global": "*", + "ember-fetch": "*", + "ember-load-initializers": "*", + "ember-maybe-import-regenerator": "*", + "ember-qunit": "*", + "ember-resolver": "*", + "ember-source": "*", + "faker": "*", + "fastboot": "*", + "jsdom": "*", + "loader.js": "*", + "miragejs": "*", + "npm-run-all": "*", + "qunit": "*", + "qunit-dom": "*" + }, + "engines": { + "node": ">= 10.*" + }, + "ember": { + "edition": "octane" + }, + "volta": { + "extends": "../../package.json" + } +} diff --git a/test-projects/01-basic-app/public/robots.txt b/test-projects/01-basic-app/public/robots.txt new file mode 100644 index 000000000..f5916452e --- /dev/null +++ b/test-projects/01-basic-app/public/robots.txt @@ -0,0 +1,3 @@ +# http://www.robotstxt.org +User-agent: * +Disallow: diff --git a/test-projects/01-basic-app/testem.js b/test-projects/01-basic-app/testem.js new file mode 100644 index 000000000..1f6c614e5 --- /dev/null +++ b/test-projects/01-basic-app/testem.js @@ -0,0 +1,24 @@ +'use strict'; + +module.exports = { + test_page: 'tests/index.html?hidepassed', + disable_watching: true, + launch_in_ci: ['Chrome'], + launch_in_dev: ['Chrome'], + browser_start_timeout: 120, + browser_args: { + Chrome: { + mode: 'ci', + args: [ + // --no-sandbox is needed when running Chrome inside a container + process.env.CI ? '--no-sandbox' : null, + '--headless', + '--disable-dev-shm-usage', + '--disable-software-rasterizer', + '--mute-audio', + '--remote-debugging-port=0', + '--window-size=1440,900', + ].filter(Boolean), + }, + }, +}; diff --git a/test-projects/01-basic-app/tests/acceptance/crud-demo-test.js b/test-projects/01-basic-app/tests/acceptance/crud-demo-test.js new file mode 100644 index 000000000..b1c5b6697 --- /dev/null +++ b/test-projects/01-basic-app/tests/acceptance/crud-demo-test.js @@ -0,0 +1,72 @@ +import { module, test } from 'qunit'; +import { + visit, + currentRouteName, + findAll, + fillIn, + click, +} from '@ember/test-helpers'; +import { setupApplicationTest } from 'ember-qunit'; +import { setupMirage } from 'ember-cli-mirage/test-support'; + +module('Acceptance | Crud demo', function (hooks) { + setupApplicationTest(hooks); + setupMirage(hooks); + + test('I can view the users', async function (assert) { + this.server.createList('user', 3); + + await visit('/crud-demo'); + + assert.equal(findAll('[data-test-id="user"]').length, 3); + }); + + test('I can create a new user', async function (assert) { + this.server.create('user', 1); + + await visit('/crud-demo'); + await fillIn('input', 'Ganon'); + await click('[data-test-id="create-user"]'); + + assert.equal(findAll('[data-test-id="user"]').length, 2); + assert.ok(this.server.db.users.length, 2); + }); + + test('I can update a user', async function (assert) { + let user = this.server.create('user', { name: 'Yehuda' }); + + await visit('/crud-demo'); + await fillIn('[data-test-id="user"] input', 'Katz'); + await click('[data-test-id="update-user"]'); + + user.reload(); + + assert.dom('[data-test-id="user"] input').hasValue('Katz'); + assert.ok(user.name, 'Katz'); + }); + + test('I can delete a user', async function (assert) { + this.server.create('user', { name: 'Yehuda' }); + + await visit('/crud-demo'); + await click('[data-test-id="delete-user"]'); + + assert.equal(findAll('[data-test-id="user"]').length, 0); + assert.equal(this.server.db.users.length, 0); + }); + + test('If the server errors on GET /users, the error template shows', async function (assert) { + this.server.get( + '/users', + { + errors: ['improper auth'], + }, + 404 + ); + + await visit('/crud-demo'); + + assert.dom('[data-test-id="error"]').hasText('improper auth'); + assert.equal(currentRouteName(), 'crud-demo_error'); + }); +}); diff --git a/test-projects/01-basic-app/tests/acceptance/ember-data-test.js b/test-projects/01-basic-app/tests/acceptance/ember-data-test.js new file mode 100644 index 000000000..5200c5ba9 --- /dev/null +++ b/test-projects/01-basic-app/tests/acceptance/ember-data-test.js @@ -0,0 +1,105 @@ +import { module, test } from 'qunit'; +import Server from 'ember-cli-mirage/server'; +import { Model } from 'ember-cli-mirage'; +import { modelFor } from 'ember-cli-mirage/ember-data'; + +const CustomTag = Model.extend(); +CustomTag.__isCustom__ = true; + +module('Acceptance | Ember Data', function (hooks) { + hooks.beforeEach(function () { + this.server = new Server({ + environment: 'development', + discoverEmberDataModels: true, + scenarios: { + default() {}, + }, + models: { + // Friend exists in dummy/app/models. We want to make sure pre-defined + // models take precedence + tag: CustomTag, + foo: Model.extend(), + }, + factories: {}, + }); + }); + + hooks.afterEach(function () { + this.server.shutdown(); + }); + + test(`Ember data models were generated and loaded`, function (assert) { + let { schema } = this.server; + let registry = schema._registry; + + assert.ok(registry.foo, 'Mirage model Foo has been registered'); + assert.ok(registry.book, 'EmberData model Book has been registered'); + assert.ok(registry.user, 'EmberData model User has been registered'); + assert.equal( + registry.user.foreignKeys.length, + 1, + 'EmberData model User has the correct relationships' + ); + assert.equal( + registry.book.foreignKeys.length, + 1, + 'EmberData model User has the correct relationships' + ); + assert.equal( + registry.user.foreignKeys[0], + 'bookIds', + 'EmberData model User has the correct relationships' + ); + assert.equal( + registry.book.foreignKeys[0], + 'userId', + 'EmberData model Book has the correct relationships' + ); + }); + + test(`It works with nested models`, function (assert) { + let { schema } = this.server; + let registry = schema._registry; + + assert.ok( + registry['things/watch'], + 'Model things/watch has been registered' + ); + }); + + test(`Defined Mirage models take precedence over autogenerated ones`, function (assert) { + let { schema } = this.server; + let registry = schema._registry; + + assert.ok(registry.tag, 'Model Tag has been registered'); + assert.ok( + registry.tag.class.__isCustom__, + 'Model Tag is not the autogenerated one' + ); + }); + + test(`Auto generated models can be extended via modelFor`, function (assert) { + let { schema } = this.server; + let registry = schema._registry; + + assert.ok(registry.book, 'Ember data model Book has been registered'); + assert.ok(modelFor('book'), 'Ember data model Book is found'); + assert.equal( + typeof modelFor('book').extend, + 'function', + 'Ember data model Book can be extended' + ); + }); + + test(`modelFor is only for auto generated models`, function (assert) { + assert.notOk( + modelFor('tag').__isCustom__, + 'Tag model is not the pre defined one' + ); + assert.throws( + () => modelFor('foo'), + /Model of type 'foo' does not exist/, + 'Pre defined mirage models cannot be found via modelFor' + ); + }); +}); diff --git a/test-projects/01-basic-app/tests/acceptance/faker-test.js b/test-projects/01-basic-app/tests/acceptance/faker-test.js new file mode 100644 index 000000000..d6dcad019 --- /dev/null +++ b/test-projects/01-basic-app/tests/acceptance/faker-test.js @@ -0,0 +1,14 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; +import { setupMirage } from 'ember-cli-mirage/test-support'; + +module('Acceptance | Faker', function (hooks) { + setupTest(hooks); + setupMirage(hooks); + + test('it works', function (assert) { + let user = this.server.create('user'); + + assert.equal(user.age, 32); + }); +}); diff --git a/test-projects/01-basic-app/tests/acceptance/fixtures-test.js b/test-projects/01-basic-app/tests/acceptance/fixtures-test.js new file mode 100644 index 000000000..ff3e286a1 --- /dev/null +++ b/test-projects/01-basic-app/tests/acceptance/fixtures-test.js @@ -0,0 +1,25 @@ +import { module, test } from 'qunit'; +import { visit } from '@ember/test-helpers'; +import { setupApplicationTest } from 'ember-qunit'; +import { setupMirage } from 'ember-cli-mirage/test-support'; + +module('Acceptance | Fixtures', function (hooks) { + setupApplicationTest(hooks); + setupMirage(hooks); + + test('I can use fixtures', async function (assert) { + this.server.loadFixtures(); + + await visit('/crud-demo'); + + assert.dom('[data-test-id="user"]').exists({ count: 1 }); + }); + + test('I can use fixtures with the filename api', async function (assert) { + this.server.loadFixtures('countries'); + + await visit('/crud-demo'); + + assert.dom('[data-test-id="user"]').doesNotExist(); + }); +}); diff --git a/test-projects/01-basic-app/tests/acceptance/identity-manager-test.js b/test-projects/01-basic-app/tests/acceptance/identity-manager-test.js new file mode 100644 index 000000000..ff654e79c --- /dev/null +++ b/test-projects/01-basic-app/tests/acceptance/identity-manager-test.js @@ -0,0 +1,14 @@ +import { module, test } from 'qunit'; +import { setupApplicationTest } from 'ember-qunit'; +import { setupMirage } from 'ember-cli-mirage/test-support'; + +module('Acceptance | Identity manager', function (hooks) { + setupApplicationTest(hooks); + setupMirage(hooks); + + test('custom identity managers work', function (assert) { + let book = this.server.create('book'); + + assert.equal(book.id, 'a'); + }); +}); diff --git a/test-projects/01-basic-app/tests/acceptance/legacy-start-mirage-test.js b/test-projects/01-basic-app/tests/acceptance/legacy-start-mirage-test.js new file mode 100644 index 000000000..728b0820b --- /dev/null +++ b/test-projects/01-basic-app/tests/acceptance/legacy-start-mirage-test.js @@ -0,0 +1,59 @@ +import { module, test } from 'qunit'; +import startApp from '../helpers/start-app'; +import destroyApp from '../helpers/destroy-app'; +import { startMirage } from 'basic-app/initializers/ember-cli-mirage'; +import ENV from 'basic-app/config/environment'; + +module('Acceptance | Starting mirage (legacy)', function (hooks) { + let app, oldEnv, addonConfig; + + hooks.beforeEach(function () { + oldEnv = ENV['ember-cli-mirage']; + ENV['ember-cli-mirage'] = addonConfig = {}; + }); + + hooks.afterEach(function () { + destroyApp(app); + ENV['ember-cli-mirage'] = oldEnv; + }); + + test('The server starts automatically when configured with enabled undefined', async function (assert) { + app = startApp(); + + assert.ok(window.server, 'There is a server after starting'); + + window.server.create('user'); + await window.visit('/crud-demo'); + + assert.equal(window.currentRouteName(), 'crud-demo'); + assert.dom('[data-test-id="user"]').exists(); + }); + + test('The server starts automatically when configured with { enabled: true }', async function (assert) { + addonConfig.enabled = true; + app = startApp(); + + assert.ok(window.server, 'There is a server after starting'); + + window.server.create('user'); + await window.visit('/crud-demo'); + + assert.equal(window.currentRouteName(), 'crud-demo'); + assert.dom('[data-test-id="user"]').exists(); + }); + + test('The server can be started manually when configured with { enabled: false }', async function (assert) { + addonConfig.enabled = false; + app = startApp(); + + assert.equal(window.server, undefined, 'There is no server at first'); + startMirage(); + assert.ok(window.server, 'There is a server after starting'); + + window.server.create('user'); + await window.visit('/crud-demo'); + + assert.equal(window.currentRouteName(), 'crud-demo'); + assert.dom('[data-test-id="user"]').exists(); + }); +}); diff --git a/test-projects/01-basic-app/tests/acceptance/request-tracking-test.js b/test-projects/01-basic-app/tests/acceptance/request-tracking-test.js new file mode 100644 index 000000000..bd5fd32c2 --- /dev/null +++ b/test-projects/01-basic-app/tests/acceptance/request-tracking-test.js @@ -0,0 +1,67 @@ +import { run } from '@ember/runloop'; +import { module, test } from 'qunit'; +import startApp from '../helpers/start-app'; +import ENV from 'basic-app/config/environment'; +import promiseAjax from '../helpers/promise-ajax'; + +let App; + +module('Acceptance | Enabling request tracking', function (hooks) { + hooks.afterEach(function () { + window.server.shutdown(); + run(App, 'destroy'); + ENV['ember-cli-mirage'].enabled = undefined; + }); + + test('Request tracking defaults to false', async function (assert) { + App = startApp(); + + await promiseAjax({ + method: 'GET', + url: '/users', + }); + + assert.equal( + window.server.pretender.handledRequests.length, + 0, + 'request tracking should be false by default' + ); + }); + + test('Request tracking treats undefined config as false', async function (assert) { + ENV['ember-cli-mirage'] = { trackRequests: undefined }; + App = startApp(); + + await promiseAjax({ + method: 'GET', + url: '/users', + }); + + assert.equal( + window.server.pretender.handledRequests.length, + 0, + 'request tracking should be false when undefined in config' + ); + }); + + test('Request tracking can be set to true in config', async function (assert) { + ENV['ember-cli-mirage'] = { trackRequests: true }; + App = startApp(); + + await promiseAjax({ + method: 'GET', + url: '/users', + }); + + assert.equal( + window.server.pretender.handledRequests.length, + 1, + 'request tracking can be turned on in config and track requests' + ); + assert.equal( + window.server.pretender.handledRequests[0].method, + 'GET', + 'tracked request method should match the requests method' + ); + }); +}); diff --git a/test-projects/01-basic-app/tests/acceptance/start-mirage-test.js b/test-projects/01-basic-app/tests/acceptance/start-mirage-test.js new file mode 100644 index 000000000..204e8a32b --- /dev/null +++ b/test-projects/01-basic-app/tests/acceptance/start-mirage-test.js @@ -0,0 +1,131 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; +import { visit, currentRouteName } from '@ember/test-helpers'; +import startMirage from 'ember-cli-mirage/start-mirage'; +import { setupMirage } from 'ember-cli-mirage/test-support'; +import ENV from 'basic-app/config/environment'; +import NestedThingModel from 'basic-app/mirage/models/nested/thing'; + +module('Acceptance | Starting mirage', function (hooks) { + let oldEnv, addonConfig, dynamicAfterEach; + + hooks.beforeEach(function () { + oldEnv = ENV['ember-cli-mirage']; + ENV['ember-cli-mirage'] = addonConfig = {}; + // When running in non-legacy mode we shoud ignore this, so we set it so we + // can make sure that tests that it doesn't cause the server to start when + // it shouldn't in the cases that test that + addonConfig.enabled = true; + + dynamicAfterEach = () => undefined; + }); + + hooks.afterEach(function () { + dynamicAfterEach(); + }); + + hooks.afterEach(function () { + ENV['ember-cli-mirage'] = oldEnv; + }); + + module('without autostart', function (hooks) { + setupTest(hooks); + + test('it does not autostart but can be started manually', async function (assert) { + assert.equal( + window.server, + undefined, + 'There is no global server at first' + ); + let server = startMirage(this.owner); + assert.ok(server, 'There is a server after starting'); + assert.ok(window.server, 'There is a global server after starting'); + dynamicAfterEach = () => server.shutdown(); + + server.create('user'); + await visit('/crud-demo'); + + assert.equal(currentRouteName(), 'crud-demo'); + assert.dom('[data-test-id="user"]').exists(); + }); + + module('nested mirage modules', function () { + test('it works', async function (assert) { + const server = startMirage(this.owner); + const model = server.create('nested/thing'); + dynamicAfterEach = () => server.shutdown(); + + assert.ok(model instanceof NestedThingModel, 'models'); + assert.equal( + model.id, + 'nested identity manager works!', + 'identity managers' + ); + assert.equal(model.name, 'nested factory works!', 'factories'); + + const { attributes } = + server.serializerOrRegistry.serialize(model).data; + assert.ok('nested_thing_name' in attributes, 'serializer'); + }); + + // factories and fixtures have to be tested separately + test('fixtures support', async function (assert) { + const server = startMirage(this.owner); + dynamicAfterEach = () => server.shutdown(); + + server.loadFixtures('nested/things'); + const model = server.schema.first('nested/thing'); + + assert.ok(model instanceof NestedThingModel, 'models'); + assert.equal( + model.id, + 'nested identity manager works!', + 'identity managers' + ); + assert.equal(model.fixtureField, 'nested fixture works!', 'fixtures'); + }); + }); + + module('setupMirage()', function (hooks) { + setupMirage(hooks); + + test('it works', async function (assert) { + assert.ok(this.server, 'There is a server'); + assert.ok(window.server, 'There is a global server'); + dynamicAfterEach = () => { + assert.notOk(this.server, 'The server was shut down'); + assert.notOk(window.server, 'The global server is gone'); + }; + + this.server.create('user'); + await visit('/crud-demo'); + + assert.equal(currentRouteName(), 'crud-demo'); + assert.dom('[data-test-id="user"]').exists(); + }); + }); + }); + + module('with autostart', function (hooks) { + hooks.beforeEach(function () { + addonConfig.autostart = true; + }); + + setupTest(hooks); + + test('it autostarts', async function (assert) { + assert.ok(this.server, 'There is a server'); + assert.ok(window.server, 'There is a global server'); + dynamicAfterEach = () => { + assert.notOk(this.server, 'The server was shut down'); + assert.notOk(window.server, 'The global server is gone'); + }; + + this.server.create('user'); + await visit('/crud-demo'); + + assert.equal(currentRouteName(), 'crud-demo'); + assert.dom('[data-test-id="user"]').exists(); + }); + }); +}); diff --git a/test-projects/01-basic-app/tests/helpers/destroy-app.js b/test-projects/01-basic-app/tests/helpers/destroy-app.js new file mode 100644 index 000000000..a935b7e33 --- /dev/null +++ b/test-projects/01-basic-app/tests/helpers/destroy-app.js @@ -0,0 +1,9 @@ +import { run } from '@ember/runloop'; + +export default function destroyApp(application) { + run(function () { + application.destroy(); + + window.server.shutdown(); + }); +} diff --git a/test-projects/01-basic-app/tests/helpers/module-for-acceptance.js b/test-projects/01-basic-app/tests/helpers/module-for-acceptance.js new file mode 100644 index 000000000..68cbbdeb8 --- /dev/null +++ b/test-projects/01-basic-app/tests/helpers/module-for-acceptance.js @@ -0,0 +1,22 @@ +import { module } from 'qunit'; +import { resolve } from 'rsvp'; +import startApp from '../helpers/start-app'; +import destroyApp from '../helpers/destroy-app'; + +export default function (name, options = {}) { + module(name, { + beforeEach() { + this.application = startApp(); + + if (options.beforeEach) { + return options.beforeEach.apply(this, arguments); + } + }, + + afterEach() { + let afterEach = + options.afterEach && options.afterEach.apply(this, arguments); + return resolve(afterEach).then(() => destroyApp(this.application)); + }, + }); +} diff --git a/test-projects/01-basic-app/tests/helpers/promise-ajax.js b/test-projects/01-basic-app/tests/helpers/promise-ajax.js new file mode 100644 index 000000000..6b746ce18 --- /dev/null +++ b/test-projects/01-basic-app/tests/helpers/promise-ajax.js @@ -0,0 +1,11 @@ +/* eslint-disable ember/no-jquery */ +import { Promise } from 'rsvp'; +import $ from 'jquery'; + +export default (options) => { + return new Promise((resolve, reject) => { + $.ajax(options) + .done((data, status, xhr) => resolve({ data, status, xhr })) + .fail((xhr, status, error) => reject({ xhr, status, error })); + }); +}; diff --git a/test-projects/01-basic-app/tests/helpers/resolver.js b/test-projects/01-basic-app/tests/helpers/resolver.js new file mode 100644 index 000000000..319b45fc1 --- /dev/null +++ b/test-projects/01-basic-app/tests/helpers/resolver.js @@ -0,0 +1,11 @@ +import Resolver from '../../resolver'; +import config from '../../config/environment'; + +const resolver = Resolver.create(); + +resolver.namespace = { + modulePrefix: config.modulePrefix, + podModulePrefix: config.podModulePrefix, +}; + +export default resolver; diff --git a/test-projects/01-basic-app/tests/helpers/start-app.js b/test-projects/01-basic-app/tests/helpers/start-app.js new file mode 100644 index 000000000..9f6aee596 --- /dev/null +++ b/test-projects/01-basic-app/tests/helpers/start-app.js @@ -0,0 +1,17 @@ +import Application from '../../app'; +import config from '../../config/environment'; +import { assign } from '@ember/polyfills'; +import { run } from '@ember/runloop'; + +export default function startApp(attrs) { + let attributes = assign({}, config.APP); + attributes.autoboot = true; + attributes = assign(attributes, attrs); // use defaults, but you can override; + + return run(() => { + let application = Application.create(attributes); + application.setupForTesting(); + application.injectTestHelpers(); + return application; + }); +} diff --git a/test-projects/01-basic-app/tests/index.html b/test-projects/01-basic-app/tests/index.html new file mode 100644 index 000000000..25cdfb5cd --- /dev/null +++ b/test-projects/01-basic-app/tests/index.html @@ -0,0 +1,40 @@ + + + + + +We ran the initializer
+{{/if}} + ++ Mirage modules in project: + + {{this.mirageModules.length}} + +
+ ++ Other modules in project: + + {{this.otherIncludedModules.length}} + +
diff --git a/test-projects/02-app-that-excludes-mirage/config/ember-cli-update.json b/test-projects/02-app-that-excludes-mirage/config/ember-cli-update.json new file mode 100644 index 000000000..192c7719f --- /dev/null +++ b/test-projects/02-app-that-excludes-mirage/config/ember-cli-update.json @@ -0,0 +1,20 @@ +{ + "schemaVersion": "1.0.0", + "packages": [ + { + "name": "ember-cli", + "version": "3.28.4", + "blueprints": [ + { + "name": "app", + "outputRepo": "https://github.com/ember-cli/ember-new-output", + "codemodsSource": "ember-app-codemods-manifest@1", + "isBaseBlueprint": true, + "options": [ + "--no-welcome" + ] + } + ] + } + ] +} diff --git a/test-projects/02-app-that-excludes-mirage/config/environment.js b/test-projects/02-app-that-excludes-mirage/config/environment.js new file mode 100644 index 000000000..688fd2276 --- /dev/null +++ b/test-projects/02-app-that-excludes-mirage/config/environment.js @@ -0,0 +1,54 @@ +'use strict'; + +module.exports = function (environment) { + let ENV = { + modulePrefix: 'basic-app', + environment, + rootURL: '/', + locationType: 'auto', + EmberENV: { + FEATURES: { + // Here you can enable experimental features on an ember canary build + // e.g. EMBER_NATIVE_DECORATOR_SUPPORT: true + }, + EXTEND_PROTOTYPES: { + // Prevent Ember Data from overriding Date.parse. + Date: false, + }, + }, + + APP: { + // Here you can pass flags/options to your application instance + // when it is created + }, + 'ember-cli-mirage': { + excludeFilesFromBuild: true, + }, + }; + + if (environment === 'development') { + // ENV.APP.LOG_RESOLVER = true; + // ENV.APP.LOG_ACTIVE_GENERATION = true; + // ENV.APP.LOG_TRANSITIONS = true; + // ENV.APP.LOG_TRANSITIONS_INTERNAL = true; + // ENV.APP.LOG_VIEW_LOOKUPS = true; + } + + if (environment === 'test') { + // Testem prefers this... + ENV.locationType = 'none'; + + // keep test console output quieter + ENV.APP.LOG_ACTIVE_GENERATION = false; + ENV.APP.LOG_VIEW_LOOKUPS = false; + + ENV.APP.rootElement = '#ember-testing'; + ENV.APP.autoboot = false; + } + + if (environment === 'production') { + // here you can enable a production-specific feature + } + + return ENV; +}; diff --git a/test-projects/02-app-that-excludes-mirage/config/optional-features.json b/test-projects/02-app-that-excludes-mirage/config/optional-features.json new file mode 100644 index 000000000..b26286e2e --- /dev/null +++ b/test-projects/02-app-that-excludes-mirage/config/optional-features.json @@ -0,0 +1,6 @@ +{ + "application-template-wrapper": false, + "default-async-observers": true, + "jquery-integration": false, + "template-only-glimmer-components": true +} diff --git a/test-projects/02-app-that-excludes-mirage/config/targets.js b/test-projects/02-app-that-excludes-mirage/config/targets.js new file mode 100644 index 000000000..0b433b73c --- /dev/null +++ b/test-projects/02-app-that-excludes-mirage/config/targets.js @@ -0,0 +1,27 @@ +'use strict'; + +const browsers = [ + 'last 1 Chrome versions', + 'last 1 Firefox versions', + 'last 1 Safari versions', +]; + +// Ember's browser support policy is changing, and IE11 support will end in +// v4.0 onwards. +// +// See https://deprecations.emberjs.com/v3.x#toc_3-0-browser-support-policy +// +// If you need IE11 support on a version of Ember that still offers support +// for it, uncomment the code block below. +// +// const isCI = Boolean(process.env.CI); +// const isProduction = process.env.EMBER_ENV === 'production'; +// +// if (isCI || isProduction) { +// browsers.push('ie 11'); +// } + +module.exports = { + browsers, + node: 'current', +}; diff --git a/test-projects/02-app-that-excludes-mirage/ember-cli-build.js b/test-projects/02-app-that-excludes-mirage/ember-cli-build.js new file mode 100644 index 000000000..48e94e9e4 --- /dev/null +++ b/test-projects/02-app-that-excludes-mirage/ember-cli-build.js @@ -0,0 +1,24 @@ +'use strict'; + +const EmberApp = require('ember-cli/lib/broccoli/ember-app'); + +module.exports = function (defaults) { + let app = new EmberApp(defaults, { + // Add options here + }); + + // Use `app.import` to add additional libraries to the generated + // output files. + // + // If you need to use different assets in different + // environments, specify an object as the first parameter. That + // object's keys should be the environment name and the values + // should be the asset to use in that environment. + // + // If the library that you are including contains AMD or ES6 + // modules that you would like to import into your application + // please specify an object with the list of modules as keys + // along with the exports of each module as its value. + + return app.toTree(); +}; diff --git a/test-projects/02-app-that-excludes-mirage/mirage/config.js b/test-projects/02-app-that-excludes-mirage/mirage/config.js new file mode 100644 index 000000000..ea9b101e1 --- /dev/null +++ b/test-projects/02-app-that-excludes-mirage/mirage/config.js @@ -0,0 +1 @@ +export default function () {} diff --git a/test-projects/02-app-that-excludes-mirage/package.json b/test-projects/02-app-that-excludes-mirage/package.json new file mode 100644 index 000000000..acc03f67e --- /dev/null +++ b/test-projects/02-app-that-excludes-mirage/package.json @@ -0,0 +1,64 @@ +{ + "name": "basic-app", + "version": "0.0.0", + "private": true, + "description": "Small description for basic-app goes here", + "license": "MIT", + "author": "", + "directories": { + "doc": "doc", + "test": "tests" + }, + "repository": "", + "scripts": { + "build": "ember build --environment=production", + "start": "ember serve", + "test": "npm-run-all lint test:*", + "test:ember": "ember test --test-port=0", + "test:fastboot": "qunit fastboot-tests/**/*.js" + }, + "devDependencies": { + "@ember/jquery": "*", + "@ember/optional-features": "*", + "@ember/test-helpers": "*", + "@embroider/test-setup": "*", + "@glimmer/component": "*", + "@glimmer/tracking": "*", + "broccoli-asset-rev": "*", + "ember-auto-import": "*", + "ember-cli": "*", + "ember-cli-babel": "*", + "ember-cli-dependency-checker": "*", + "ember-cli-fastboot": "*", + "ember-cli-htmlbars": "*", + "ember-cli-inject-live-reload": "*", + "ember-cli-mirage": "*", + "ember-cli-sri": "*", + "ember-cli-terser": "*", + "ember-data": "*", + "ember-export-application-global": "*", + "ember-fetch": "*", + "ember-load-initializers": "*", + "ember-maybe-import-regenerator": "*", + "ember-qunit": "*", + "ember-resolver": "*", + "ember-source": "*", + "faker": "*", + "fastboot": "*", + "jsdom": "*", + "loader.js": "*", + "miragejs": "*", + "npm-run-all": "*", + "qunit": "*", + "qunit-dom": "*" + }, + "engines": { + "node": ">= 10.*" + }, + "ember": { + "edition": "octane" + }, + "volta": { + "extends": "../../package.json" + } +} diff --git a/test-projects/02-app-that-excludes-mirage/public/robots.txt b/test-projects/02-app-that-excludes-mirage/public/robots.txt new file mode 100644 index 000000000..f5916452e --- /dev/null +++ b/test-projects/02-app-that-excludes-mirage/public/robots.txt @@ -0,0 +1,3 @@ +# http://www.robotstxt.org +User-agent: * +Disallow: diff --git a/test-projects/02-app-that-excludes-mirage/testem.js b/test-projects/02-app-that-excludes-mirage/testem.js new file mode 100644 index 000000000..1f6c614e5 --- /dev/null +++ b/test-projects/02-app-that-excludes-mirage/testem.js @@ -0,0 +1,24 @@ +'use strict'; + +module.exports = { + test_page: 'tests/index.html?hidepassed', + disable_watching: true, + launch_in_ci: ['Chrome'], + launch_in_dev: ['Chrome'], + browser_start_timeout: 120, + browser_args: { + Chrome: { + mode: 'ci', + args: [ + // --no-sandbox is needed when running Chrome inside a container + process.env.CI ? '--no-sandbox' : null, + '--headless', + '--disable-dev-shm-usage', + '--disable-software-rasterizer', + '--mute-audio', + '--remote-debugging-port=0', + '--window-size=1440,900', + ].filter(Boolean), + }, + }, +}; diff --git a/test-projects/02-app-that-excludes-mirage/tests/acceptance/modules-test.js b/test-projects/02-app-that-excludes-mirage/tests/acceptance/modules-test.js new file mode 100644 index 000000000..8aa58e9b5 --- /dev/null +++ b/test-projects/02-app-that-excludes-mirage/tests/acceptance/modules-test.js @@ -0,0 +1,14 @@ +import { module, test } from 'qunit'; +import { visit } from '@ember/test-helpers'; +import { setupApplicationTest } from 'ember-qunit'; + +module('Acceptance | modules', function (hooks) { + setupApplicationTest(hooks); + + test('only 1 module (the no-op initializer) is included in the build', async function (assert) { + await visit('/'); + + assert.dom('[data-test-id="mirage-module-count"]').hasText('0'); + assert.dom('[data-test-id="other-module-count"]').hasText('1'); + }); +}); diff --git a/test-projects/02-app-that-excludes-mirage/tests/acceptance/pre-mirage-initializer-test.js b/test-projects/02-app-that-excludes-mirage/tests/acceptance/pre-mirage-initializer-test.js new file mode 100644 index 000000000..54c39b6de --- /dev/null +++ b/test-projects/02-app-that-excludes-mirage/tests/acceptance/pre-mirage-initializer-test.js @@ -0,0 +1,13 @@ +import { module, test } from 'qunit'; +import { visit } from '@ember/test-helpers'; +import { setupApplicationTest } from 'ember-qunit'; + +module('Acceptance | noop initializer test', function (hooks) { + setupApplicationTest(hooks); + + test('visiting /noop-initializer-test', async function (assert) { + await visit('/'); + + assert.dom('[data-test-id="wifi-connected"]').exists({ count: 1 }); + }); +}); diff --git a/test-projects/02-app-that-excludes-mirage/tests/helpers/destroy-app.js b/test-projects/02-app-that-excludes-mirage/tests/helpers/destroy-app.js new file mode 100644 index 000000000..07753ba46 --- /dev/null +++ b/test-projects/02-app-that-excludes-mirage/tests/helpers/destroy-app.js @@ -0,0 +1,11 @@ +import { run } from '@ember/runloop'; + +export default function destroyApp(application) { + run(function () { + application.destroy(); + + if (window.server) { + window.server.shutdown(); + } + }); +} diff --git a/test-projects/02-app-that-excludes-mirage/tests/helpers/module-for-acceptance.js b/test-projects/02-app-that-excludes-mirage/tests/helpers/module-for-acceptance.js new file mode 100644 index 000000000..68cbbdeb8 --- /dev/null +++ b/test-projects/02-app-that-excludes-mirage/tests/helpers/module-for-acceptance.js @@ -0,0 +1,22 @@ +import { module } from 'qunit'; +import { resolve } from 'rsvp'; +import startApp from '../helpers/start-app'; +import destroyApp from '../helpers/destroy-app'; + +export default function (name, options = {}) { + module(name, { + beforeEach() { + this.application = startApp(); + + if (options.beforeEach) { + return options.beforeEach.apply(this, arguments); + } + }, + + afterEach() { + let afterEach = + options.afterEach && options.afterEach.apply(this, arguments); + return resolve(afterEach).then(() => destroyApp(this.application)); + }, + }); +} diff --git a/test-projects/02-app-that-excludes-mirage/tests/helpers/promise-ajax.js b/test-projects/02-app-that-excludes-mirage/tests/helpers/promise-ajax.js new file mode 100644 index 000000000..6b746ce18 --- /dev/null +++ b/test-projects/02-app-that-excludes-mirage/tests/helpers/promise-ajax.js @@ -0,0 +1,11 @@ +/* eslint-disable ember/no-jquery */ +import { Promise } from 'rsvp'; +import $ from 'jquery'; + +export default (options) => { + return new Promise((resolve, reject) => { + $.ajax(options) + .done((data, status, xhr) => resolve({ data, status, xhr })) + .fail((xhr, status, error) => reject({ xhr, status, error })); + }); +}; diff --git a/test-projects/02-app-that-excludes-mirage/tests/helpers/resolver.js b/test-projects/02-app-that-excludes-mirage/tests/helpers/resolver.js new file mode 100644 index 000000000..319b45fc1 --- /dev/null +++ b/test-projects/02-app-that-excludes-mirage/tests/helpers/resolver.js @@ -0,0 +1,11 @@ +import Resolver from '../../resolver'; +import config from '../../config/environment'; + +const resolver = Resolver.create(); + +resolver.namespace = { + modulePrefix: config.modulePrefix, + podModulePrefix: config.podModulePrefix, +}; + +export default resolver; diff --git a/test-projects/02-app-that-excludes-mirage/tests/helpers/start-app.js b/test-projects/02-app-that-excludes-mirage/tests/helpers/start-app.js new file mode 100644 index 000000000..9f6aee596 --- /dev/null +++ b/test-projects/02-app-that-excludes-mirage/tests/helpers/start-app.js @@ -0,0 +1,17 @@ +import Application from '../../app'; +import config from '../../config/environment'; +import { assign } from '@ember/polyfills'; +import { run } from '@ember/runloop'; + +export default function startApp(attrs) { + let attributes = assign({}, config.APP); + attributes.autoboot = true; + attributes = assign(attributes, attrs); // use defaults, but you can override; + + return run(() => { + let application = Application.create(attributes); + application.setupForTesting(); + application.injectTestHelpers(); + return application; + }); +} diff --git a/test-projects/02-app-that-excludes-mirage/tests/index.html b/test-projects/02-app-that-excludes-mirage/tests/index.html new file mode 100644 index 000000000..25cdfb5cd --- /dev/null +++ b/test-projects/02-app-that-excludes-mirage/tests/index.html @@ -0,0 +1,40 @@ + + + + + ++ {{this.model.responseJSON.message}} +
diff --git a/tests/dummy/app/pods/blog/index/route.js b/tests/dummy/app/pods/blog/index/route.js new file mode 100644 index 000000000..2099c3b01 --- /dev/null +++ b/tests/dummy/app/pods/blog/index/route.js @@ -0,0 +1,7 @@ +import Route from '@ember/routing/route'; + +export default class extends Route { + model() { + return this.store.findAll('post'); + } +} diff --git a/tests/dummy/app/pods/blog/index/template.hbs b/tests/dummy/app/pods/blog/index/template.hbs new file mode 100644 index 000000000..ab25bf282 --- /dev/null +++ b/tests/dummy/app/pods/blog/index/template.hbs @@ -0,0 +1,16 @@ ++ Spend less time wiring up HTTP stubs, and get back to developing your app. +
++ Use factories to define your server's state per test. Acceptance testing just got a whole lot easier. +
++ Share a functional prototype of your app that runs entirely in the client – before writing a single line of your API. +
+This page doesn't exist.
{{friend.name}} is your {{friend.age}}-year-old friend.
-{{/each}} diff --git a/tests/dummy/app/templates/contact.hbs b/tests/dummy/app/templates/contact.hbs deleted file mode 100644 index a90a2cbee..000000000 --- a/tests/dummy/app/templates/contact.hbs +++ /dev/null @@ -1,13 +0,0 @@ -{{link-to 'Back home' 'contacts'}} - -The contact is {{model.name}}
- -There was an error: {{error}}
-{{else}} - {{#each model as |contact|}} -{{link-to contact.name 'contact' contact}}
- {{/each}} -{{/if}} - -{{friend.name}} is your {{friend.age}}-year-old friend.
-{{/each}} diff --git a/tests/dummy/app/templates/pets.hbs b/tests/dummy/app/templates/pets.hbs deleted file mode 100644 index 0a6d37868..000000000 --- a/tests/dummy/app/templates/pets.hbs +++ /dev/null @@ -1,11 +0,0 @@ -{{#if error}} -There was an error: {{error}}
-{{else}} -
Comments
+ + {{#each this.model.comments as |comment|}} ++ + {{comment.user.username}} + + commented + + {{moment-from comment.createdAt}} + +
+ {{comment.htmlBody}} ++ Want to chime in? + + {{!-- Reply to Issue #{{model.id}}. --}} + View the thread on GitHub. +
+