Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
export type MockGoogleAddressComponent = {
import Service from '@ember/service';

import { AutocompleteHandlerBase } from '@upfluence/ember-upf-utils/services/autocomplete-handler';

type MockGoogleAddressComponent = {
types: string[];
long_name: string;
short_name: string;
};

export type MockPlaceResult = {
type MockPlaceResult = {
address_components?: MockGoogleAddressComponent[];
formatted_address?: string;
};

export class MockAutocomplete {
class AutocompleteHandlerServiceMock extends Service implements AutocompleteHandlerBase<MockLoader> {
private mockLoader: MockLoader = new MockLoader({ apiKey: 'test-key' });

getLoader(): MockLoader {
return this.mockLoader;
}
}

class MockAutocomplete {
private listeners: Map<string, Function[]> = new Map();
private mockPlace: MockPlaceResult = {};

Expand Down Expand Up @@ -41,7 +53,7 @@ export class MockAutocomplete {
}
}

export class MockLoader {
class MockLoader {
private mockAutocompleteInstance: MockAutocomplete | null = null;

constructor(public config?: Record<string, any>) {}
Expand All @@ -66,7 +78,7 @@ export class MockLoader {
}
}

export function createSampleAddressComponents(
function createSampleAddressComponents(
overrides: Partial<{
streetNumber: string;
route: string;
Expand Down Expand Up @@ -149,7 +161,7 @@ export function createSampleAddressComponents(
return components;
}

export function createMockPlaceResult(
function createMockPlaceResult(
addressComponents: MockGoogleAddressComponent[],
formattedAddress?: string
): MockPlaceResult {
Expand All @@ -158,3 +170,11 @@ export function createMockPlaceResult(
formatted_address: formattedAddress
};
}

export {
AutocompleteHandlerServiceMock,
MockAutocomplete,
MockLoader,
createSampleAddressComponents,
createMockPlaceResult
};
25 changes: 10 additions & 15 deletions addon/modifiers/setup-autocomplete.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import Modifier, { type ArgsFor, type PositionalArgs, type NamedArgs } from 'ember-modifier';
import { registerDestructor } from '@ember/destroyable';
import { assert } from '@ember/debug';
import { getOwner } from '@ember/application';
import { isTesting } from '@embroider/macros';

import { Loader } from '@googlemaps/js-api-loader';
import { inject as service } from '@ember/service';

import { parseAddressComponents } from '@upfluence/ember-upf-utils/utils/address-parser';
import { MockLoader } from '@upfluence/ember-upf-utils/utils/google-maps-mock';
import { CountryData } from '@upfluence/oss-components/utils/country-codes';
import type AutocompleteHandlerService from '@upfluence/ember-upf-utils/services/autocomplete-handler';

import { Loader } from '@googlemaps/js-api-loader';

type GooglePlaceResult = google.maps.places.PlaceResult;
type GoogleAutocomplete = google.maps.places.Autocomplete;
Expand All @@ -28,7 +27,6 @@ interface SetupAutocompleteSignature {
Args: {
Named: {
callback(result: AutocompletionAddress): void;
loader?: Loader;
};
};
}
Expand Down Expand Up @@ -57,6 +55,8 @@ function cleanup(instance: SetupAutocompleteModifier): void {
}

export default class SetupAutocompleteModifier extends Modifier<SetupAutocompleteSignature> {
@service declare autocompleteHandler: AutocompleteHandlerService;

targetElement: HTMLElement | null = null;
targetInput: HTMLInputElement | null = null;
result: AutocompletionAddress | null = null;
Expand All @@ -72,7 +72,7 @@ export default class SetupAutocompleteModifier extends Modifier<SetupAutocomplet
modify(
element: HTMLElement,
_: PositionalArgs<SetupAutocompleteSignature>,
{ callback, loader }: NamedArgs<SetupAutocompleteSignature>
{ callback }: NamedArgs<SetupAutocompleteSignature>
): void {
const input: HTMLInputElement | null = this.getInputElement(element);
if (!input) return;
Expand All @@ -87,7 +87,7 @@ export default class SetupAutocompleteModifier extends Modifier<SetupAutocomplet

if (!this.targetElement) {
this.setupTargetElement(element, input);
this.setupAutoComplete(loader);
this.setupAutoComplete();
}
}

Expand Down Expand Up @@ -134,13 +134,8 @@ export default class SetupAutocompleteModifier extends Modifier<SetupAutocomplet
return element.tagName === 'INPUT' && (element as HTMLInputElement).type === 'text';
}

private setupAutoComplete(loader?: Loader): Promise<void> {
const loaderInstance: Loader | MockLoader = isTesting()
? loader ?? new MockLoader({ apiKey: 'test-key' })
: new Loader({
apiKey: getOwner(this).resolveRegistration('config:environment').google_map_api_key,
version: 'weekly'
});
private setupAutoComplete(): Promise<void> {
const loaderInstance: Loader = this.autocompleteHandler.getLoader();

// @ts-ignore
return loaderInstance.importLibrary('places').then(({ Autocomplete }: google.maps.PlacesLibrary) => {
Expand Down
23 changes: 23 additions & 0 deletions addon/services/autocomplete-handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Service from '@ember/service';
import { getOwner } from '@ember/application';

import { Loader } from '@googlemaps/js-api-loader';

export interface AutocompleteHandlerBase<T> {
getLoader(): T;
}

export default class AutocompleteHandler extends Service implements AutocompleteHandlerBase<Loader> {
getLoader(): Loader {
return new Loader({
apiKey: getOwner(this).resolveRegistration('config:environment').google_map_api_key,
version: 'weekly'
});
}
}

declare module '@ember/service' {
interface Registry {
'autocomplete-handler': AutocompleteHandler;
}
}
1 change: 1 addition & 0 deletions app/services/autocomplete-handler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from '@upfluence/ember-upf-utils/services/autocomplete-handler';
1 change: 1 addition & 0 deletions tests/dummy/config/environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ module.exports = function (environment) {

ENV.APP.rootElement = '#ember-testing';
ENV.APP.autoboot = false;
ENV.google_map_api_key = 'foobar';
}

if (environment === 'production') {
Expand Down
1 change: 0 additions & 1 deletion tests/integration/components/http-errors-code-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { setupRenderingTest } from 'ember-qunit';
import { click, render } from '@ember/test-helpers';
import { hbs } from 'ember-cli-htmlbars';
import Service from '@ember/service';
// @ts-ignore
import { setupIntl } from 'ember-intl/test-support';
import sinon from 'sinon';

Expand Down
3 changes: 3 additions & 0 deletions tests/integration/components/utils/address-form-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import EmberObject from '@ember/object';
import { click, fillIn, findAll, render, typeIn } from '@ember/test-helpers';
import sinon from 'sinon';

import { AutocompleteHandlerServiceMock } from '@upfluence/ember-upf-utils/test-support/services/autocomplete-handler';

module('Integration | Component | utils/address-form', function (hooks) {
setupRenderingTest(hooks);
setupIntl(hooks);

hooks.beforeEach(function () {
this.owner.register('service:autocomplete-handler', AutocompleteHandlerServiceMock);
this.address = EmberObject.create({
firstName: 'iam',
lastName: 'groot',
Expand Down
3 changes: 3 additions & 0 deletions tests/integration/components/utils/address-inline-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import EmberObject from '@ember/object';
import { render, typeIn } from '@ember/test-helpers';
import sinon from 'sinon';

import { AutocompleteHandlerServiceMock } from '@upfluence/ember-upf-utils/test-support/services/autocomplete-handler';

module('Integration | Component | utils/address-inline', function (hooks) {
setupRenderingTest(hooks);
setupIntl(hooks);

hooks.beforeEach(function () {
this.owner.register('service:autocomplete-handler', AutocompleteHandlerServiceMock);
this.address = EmberObject.create({
address: '123 Main St',
resolved_address: null
Expand Down
44 changes: 20 additions & 24 deletions tests/integration/modifiers/setup-autocomplete-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@ import { type AutocompletionAddress } from '@upfluence/ember-upf-utils/modifiers

import {
createMockPlaceResult,
createSampleAddressComponents,
MockLoader
} from '@upfluence/ember-upf-utils/utils/google-maps-mock';
createSampleAddressComponents
} from '@upfluence/ember-upf-utils/test-support/services/autocomplete-handler';
import { AutocompleteHandlerServiceMock } from '@upfluence/ember-upf-utils/test-support/services/autocomplete-handler';

module('Integration | Modifier | setup-autocomplete', function (hooks) {
setupRenderingTest(hooks);

hooks.beforeEach(function () {
this.mockLoader = new MockLoader({ apiKey: 'test-key' });
this.owner.register('service:autocomplete-handler', AutocompleteHandlerServiceMock);
const service = this.owner.lookup('service:autocomplete-handler');
this.mockLoader = service.getLoader();
});

module('Element setup', () => {
test('it works with a text input element directly', async function (assert) {
await render(
hbs`<div><input type="text" {{setup-autocomplete callback=(fn (mut this.result)) loader=this.mockLoader}} /></div>`
);
await render(hbs`<div><input type="text" {{setup-autocomplete callback=(fn (mut this.result))}} /></div>`);

assert.dom('input[type="text"]').exists();
const input = find('input[type="text"]');
Expand All @@ -30,7 +30,7 @@ module('Integration | Modifier | setup-autocomplete', function (hooks) {

test('it works with input inside a container element', async function (assert) {
await render(hbs`
<div {{setup-autocomplete callback=(fn (mut this.result)) loader=this.mockLoader}}>
<div {{setup-autocomplete callback=(fn (mut this.result))}}>
<input type="text" />
</div>
`);
Expand All @@ -49,7 +49,7 @@ module('Integration | Modifier | setup-autocomplete', function (hooks) {
};

await render(hbs`
<div><input type="text" {{setup-autocomplete callback=this.handleAddress loader=this.mockLoader}} /></div>
<div><input type="text" {{setup-autocomplete callback=this.handleAddress}} /></div>
`);

const mockAutocomplete = this.mockLoader.getMockAutocompleteInstance();
Expand All @@ -71,7 +71,7 @@ module('Integration | Modifier | setup-autocomplete', function (hooks) {
};

await render(hbs`
<input type="text" {{setup-autocomplete callback=this.handleAddress loader=this.mockLoader}} />
<input type="text" {{setup-autocomplete callback=this.handleAddress}} />
`);

const mockAutocomplete = this.mockLoader.getMockAutocompleteInstance();
Expand All @@ -84,7 +84,7 @@ module('Integration | Modifier | setup-autocomplete', function (hooks) {
module('Cleanup', () => {
test('pac-container is removed on teardown', async function (assert) {
await render(hbs`
<input type="text" {{setup-autocomplete callback=(fn (mut this.result)) loader=this.mockLoader}} />
<input type="text" {{setup-autocomplete callback=(fn (mut this.result))}} />
`);

const pacContainer = document.createElement('div');
Expand All @@ -100,7 +100,7 @@ module('Integration | Modifier | setup-autocomplete', function (hooks) {

test('wrapper is properly unwrapped during cleanup', async function (assert) {
await render(
hbs`<div><input type="text" id="test-input" {{setup-autocomplete callback=(fn (mut this.result)) loader=this.mockLoader}} /></div>`
hbs`<div><input type="text" id="test-input" {{setup-autocomplete callback=(fn (mut this.result))}} /></div>`
);

assert.dom('#test-input').exists();
Expand All @@ -117,9 +117,7 @@ module('Integration | Modifier | setup-autocomplete', function (hooks) {
});

test('cleanup handles already removed elements gracefully', async function (assert) {
await render(
hbs`<div><input type="text" {{setup-autocomplete callback=(fn (mut this.result)) loader=this.mockLoader}} /></div>`
);
await render(hbs`<div><input type="text" {{setup-autocomplete callback=(fn (mut this.result))}} /></div>`);

assert.dom('input[type="text"]').exists();
const input = find('input[type="text"]');
Expand All @@ -135,7 +133,7 @@ module('Integration | Modifier | setup-autocomplete', function (hooks) {

test('wrapper is not created when modifier is on container element', async function (assert) {
await render(hbs`
<div {{setup-autocomplete callback=(fn (mut this.result)) loader=this.mockLoader}}>
<div {{setup-autocomplete callback=(fn (mut this.result))}}>
<input type="text" id="container-input" />
</div>
`);
Expand All @@ -156,7 +154,7 @@ module('Integration | Modifier | setup-autocomplete', function (hooks) {
this.value = '123 Main Street';

await render(hbs`
<input type="text" value={{this.value}} {{setup-autocomplete callback=(fn (mut this.result)) loader=this.mockLoader}} />
<input type="text" value={{this.value}} {{setup-autocomplete callback=(fn (mut this.result))}} />
`);

assert.dom('input[type="text"]').hasValue('123 Main Street');
Expand All @@ -169,7 +167,7 @@ module('Integration | Modifier | setup-autocomplete', function (hooks) {
id="address-input"
class="custom-input"
placeholder="Enter address"
{{setup-autocomplete callback=(fn (mut this.result)) loader=this.mockLoader}}
{{setup-autocomplete callback=(fn (mut this.result))}}
/>
`);

Expand All @@ -189,7 +187,7 @@ module('Integration | Modifier | setup-autocomplete', function (hooks) {
};

await render(hbs`
<input type="text" {{setup-autocomplete callback=this.handleAddress loader=this.mockLoader}} />
<input type="text" {{setup-autocomplete callback=this.handleAddress}} />
`);

const mockAutocomplete = this.mockLoader.getMockAutocompleteInstance();
Expand All @@ -215,7 +213,7 @@ module('Integration | Modifier | setup-autocomplete', function (hooks) {
);
});

await render(hbs`<div><input type="text" {{setup-autocomplete loader=this.mockLoader}} /></div>`);
await render(hbs`<div><input type="text" {{setup-autocomplete}} /></div>`);
});

test('handles missing input element gracefully', async function (assert) {
Expand All @@ -227,7 +225,7 @@ module('Integration | Modifier | setup-autocomplete', function (hooks) {
);
});

await render(hbs`<div {{setup-autocomplete callback=(fn (mut this.result)) loader=this.mockLoader}}></div>`);
await render(hbs`<div {{setup-autocomplete callback=(fn (mut this.result))}}></div>`);
});

test('handles missing input element in its children gracefully', async function (assert) {
Expand All @@ -239,9 +237,7 @@ module('Integration | Modifier | setup-autocomplete', function (hooks) {
);
});

await render(
hbs`<div {{setup-autocomplete callback=(fn (mut this.result)) loader=this.mockLoader}}><div></div></div>`
);
await render(hbs`<div {{setup-autocomplete callback=(fn (mut this.result))}}><div></div></div>`);
});
});
});
Expand Down
Loading