Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added additional setter methods for select lists #86

Merged
merged 1 commit into from
Apr 15, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,11 +169,26 @@ setTextAreaValue(element("textarea"), "Sasquatch") //Text area now has value "Sa
setCheckboxValue(element("input[type=check]"), true) //Checkbox is now checked
setRadioButton(element("input[type=radio]"), true) //Radio button is now selected
setSelectValue(element("select"), "Hancock") //Dropdown list now has the value "Hancock" selected
setSelectIndex(element("select"), 1) //Dropdown list now has the second option selected

```

These work with any DOM element reference, not just those returned by ng-units selection methods. They can be used
in traditional TestBed tests if desired.

#### Select lists and `[ngValue]`
Using `[ngValue]` for select list option bindings complicates setting a value slightly. The bound values can be things
other than strings, and consequently the value is not bound to the DOM. This makes determining which option to select more complicated.

If you know the index of the option you want you can use `setSelectIndex(element("select"), index)` to select the value

If you have access to a list of all the objects that are bound as option values you can use `setSelectFromOptions()` to select the value:
```typescript
const listOptions = [{ message: "Hello"}, { message: "Goodbye"}]
setSelectFromOptions(element("select"), { message: "Goodbye"}, listOptions)
```


#### Setting component inputs
Initial values for component inputs can be set prior to component instantiation (so they are properly present at
OnInit time) with the test builder method`.setInput()`.
Expand Down
115 changes: 115 additions & 0 deletions src/dom.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {
selectComponents,
setCheckboxValue,
setRadioButton,
setSelectFromOptions,
setSelectIndex,
setSelectValue,
setTextAreaValue,
setTextInputValue,
Expand Down Expand Up @@ -119,6 +121,117 @@ describe("DOM", () => {
expect(subject.selectValue).to.equal("Adios")
})


})

describe("setSelectIndex() sets the value of select elements", () => {

it("when options have value attributes", () => {
@Component({
selector: "parent",
template: `
<select [(ngModel)]="selectValue">
<option></option>
<option value="Hola">Hello</option>
<option value="Adios">Goodbye</option>
</select>
`,
})
class TestComponent {
public selectValue = ""
}
const {subject, subjectElement, fixture} = setupTestModule(TestComponent)


setSelectIndex(subjectElement.querySelector("select"), 2)
fixture.detectChanges()

expect(subject.selectValue).to.equal("Adios")
})

it("when options have ngValue attributes", () => {
@Component({
selector: "parent",
template: `
<select [(ngModel)]="selectValue">
<option [ngValue]="null"></option>
<option [ngValue]="{ message: 'Hola' }">Hello</option>
<option [ngValue]="{ message: 'Adios' }">Goodbye</option>
</select>
`,
})
class TestComponent {
public selectValue = null
}
const {subject, subjectElement, fixture} = setupTestModule(TestComponent)

setSelectIndex(subjectElement.querySelector("select"), 1)
fixture.detectChanges()
expect(subject.selectValue).to.deep.equal({ message: "Hola" })

setSelectIndex(subjectElement.querySelector("select"), 0)
fixture.detectChanges()
expect(subject.selectValue).to.equal(null)
})

})

describe("setSelectFromOptions() sets the value of select elements", () => {

it("when options have ngValue attributes", () => {
@Component({
selector: "parent",
template: `
<select [(ngModel)]="selectValue">
<option *ngFor="let option of allOptions" [ngValue]="option">{{option?.label}}</option>
</select>
`,
})
class TestComponent {
public allOptions = [
null,
{ label: "Hello", value: "Hola" },
{ bar: "Adios" },
]

public selectValue = null
}
const {subject, subjectElement, fixture} = setupTestModule(TestComponent)


setSelectFromOptions(subjectElement.querySelector("select"), { bar: "Adios" }, subject.allOptions)
fixture.detectChanges()

expect(subject.selectValue).to.deep.equal({ bar: "Adios" })
})

it("when options have value attributes", () => {
@Component({
selector: "parent",
template: `
<select [(ngModel)]="selectValue">
<option *ngFor="let option of allOptions" value="{{option?.value}}">{{option?.label}}</option>
</select>
`,
})
class TestComponent {
public allOptions = [
null,
{ label: "Hello", value: "Hola" },
{ label: "Goodbye", value: "Adios" },
]

public selectValue = null
}
const {subject, subjectElement, fixture} = setupTestModule(TestComponent)


setSelectFromOptions(subjectElement.querySelector("select"), { label: "Goodbye", value: "Adios" }, subject.allOptions)
fixture.detectChanges()

expect(subject.selectValue).to.equal("Adios")
})

})

it('setRadioButton() sets the value of <input type="radio"> elements', () => {
Expand Down Expand Up @@ -464,6 +577,8 @@ describe("DOM", () => {
["name", "method" ],
[setTextInputValue.name, setTextInputValue ],
[setSelectValue.name, setSelectValue ],
[setSelectIndex.name, setSelectIndex ],
[setSelectFromOptions.name, setSelectFromOptions],
[setTextAreaValue.name, setTextAreaValue ],
[setCheckboxValue.name, setCheckboxValue ],
[setRadioButton.name, setRadioButton ],
Expand Down
18 changes: 15 additions & 3 deletions src/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {isNil, isString, findIndex} from "lodash"
import {By} from "@angular/platform-browser"
import {selectorOf} from "./selector-of"
import {Type} from "@angular/core"
import { isEqual } from "lodash"

function doIfElementPresent<T>(element: T | null, action: (item: T) => void) {
if (isNil(element)) {
Expand All @@ -20,13 +21,24 @@ export function setTextInputValue(input: Element | null, value: string): void {
})
}

export function setSelectIndex(selectBox: Element | null, index: number): void {
doIfElementPresent(selectBox, selectBox => {
(selectBox as any).selectedIndex = index
trigger(selectBox, "change")
})
}

export function setSelectValue(selectBox: Element | null, value: string): void {
doIfElementPresent(selectBox, selectBox => {
(selectBox as any).selectedIndex = findIndex(selectBox.children, option =>
option.getAttribute("value") === value || option.textContent === value)
const index = findIndex(selectBox.children, option => option.getAttribute("value") === value || option.textContent === value)
setSelectIndex(selectBox, index)
})
}

trigger(selectBox, "change")
export function setSelectFromOptions(selectBox: Element | null, optionToSelection: any, allOptions: any[]): void {
doIfElementPresent(selectBox, selectBox => {
const index = findIndex(allOptions, option => isEqual(option, optionToSelection))
setSelectIndex(selectBox, index)
})
}

Expand Down