First Xenon Component
Now we need to create xenon objects to encapulate a component's elements. We start by creating a ChatHeader
xenon object which has a field title
. In our E2E's we do expect(chatPage.header.title.text()).toBe("my chat")
. This will use the css path .chat-header .title
for element. We have inlined the ChatHeader
class in the test but this can live elsewhere and be imported into the spec.
import {Component, List, defaults, field} from "xenon";
@defaults({css:".chat-header"})
class ChatHeader extends Component {
@field(Component, {css:".title"})
title:Component
}
class ChatPage extends Component {
@field(ChatHeader)
header:ChatHeader
@field(Component, {css:".message"})
chatbox:Component
@field(Component, {css:".send-action"})
submitChat:Component
}
describe("Chat App features", () => {
it("general acceptance", () => {
browser.get("http://localhost:3002")
let chatPage:ChatPage = new ChatPage();
expect(chatPage.header.isVisible()).toBe(true)
expect(chatPage.header.title.text()).toBe("my chat")
chatPage.chatbox.type("hello")
chatPage.submitChat.click()
})
})
Reusable Xenon Components
ChatHeader
may be reused in other parts of the page so we need to change the locator. Here we added an method id
which builds the css locator by calling this.css(selector)
.
import {Component, List, defaults, field} from "xenon";
@defaults({css:".chat-header"})
class ChatHeader extends Component {
@field(Component, {css:".title"})
title:Component
id(id:string) {
this.css(".header--"+id);
}
}
class ChatPage extends Component {
@field(ChatHeader, {id:"header"})
header:ChatHeader
@field(ChatHeader, {id:"second-header"})
secondHeader:ChatHeader
@field(Component, {css:".message"})
chatbox:Component
@field(Component, {css:".send-action"})
submitChat:Component
}
describe("Chat App features", () => {
it("general acceptance", () => {
browser.get("http://localhost:3002")
let chatPage:ChatPage = new ChatPage();
expect(chatPage.header.isVisible()).toBe(true)
expect(chatPage.header.title.text()).toBe("my chat")
expect(chatPage.secondHeader.isVisible()).toBe(true)
expect(chatPage.secondHeader.title.getText()).toBe("my second header")
chatPage.chatbox.type("hello")
chatPage.submitChat.click()
})
})
Custom methods
You can create custom methods on xenon components. We have refactored the above example with sendMessage(message)
method.
import {Component, List, defaults, field} from "xenon";
@defaults({css:".chat-header"})
class ChatHeader extends Component {
@field(Component, {css:".title"})
title:Component
id(id:string) {
this.css(".header--"+id);
}
}
class ChatPage extends Component {
@field(ChatHeader, {id:"header"})
header:ChatHeader
@field(ChatHeader, {id:"second-header"})
secondHeader:ChatHeader
@field(Component, {css:".message"})
chatbox:Component
@field(Component, {css:".send-action"})
submitChat:Component
sendMessage(message:string) {
this.chatbox.type(message)
this.submitChat.click()
}
}
describe("Chat App features", () => {
it("general acceptance", () => {
browser.get("http://localhost:3002")
let chatPage:ChatPage = new ChatPage();
expect(chatPage.header.isVisible()).toBe(true)
expect(chatPage.header.title.text()).toBe("my chat")
expect(chatPage.secondHeader.isVisible()).toBe(true)
expect(chatPage.secondHeader.title.getText()).toBe("my second header")
chatPage.sendMessage("hello")
})
})