-
Notifications
You must be signed in to change notification settings - Fork 3k
Closed
Labels
Description
This is a:
- Bug Report
Bug Report
Current Behavior:
Angular-ui-router doesn't recognize the way the service resolves the promise, making imposible the HTML to render when I try to use async/awaits, but when I use normal promises, this works.
The problem: Async/Awaits vs Normal promise
//This doesn't work
async getTodos() \{
const apiResponse = await this.http.get(this.url)
return apiResponse.data.todos
}
//this works
getTodos() \{
return this.http.get(this.url).then(res => res.data.todos)
}
The test
import { routes } from "routes"
import { TodoListComponent } from "components/todoList.component"
import { TodoService } from "services/todo.service"
describe("TodoListComponent rendering and interaction on '/' base path", () => {
const todosHttpResponse = require(`${__dirname}/../../stubs/todos_get.json`)
const treeDOMBody = document.querySelectorAll("body")[0]
//Register once time all the ones involved in the scene on the angular module system
beforeAll(() => {
angular
.module("Test", [
"ui.router"
])
.config(routes)
.constant("BASE_URL", "http://localhost:5000/api")
.component("todoList", TodoListComponent)
.service("TodoService", TodoService)
})
//Inject the "Test" module. (@TODO: Research why this module injection it's necessary en each test)
beforeEach(angular.mock.module("Test"))
//Configure the basic setup for each test
beforeEach(inject(($rootScope, $compile, $location, $httpBackend) => {
//@TODO: It's possible inject the $httpBackend once instead in each test?
//1st Building the scene: register the http interceptor
$httpBackend
.whenGET(/.+\/todos/)
.respond((method, url, data, headers, params) => {
return [200, todosHttpResponse]
})
//2nd Building the scene: render the root element of scene. In this case
//it is the ui-router view
const componentDOMelement = angular.element("<div ui-view></div>")
//@TODO: It's possible avoid this js-dom hack?
document.body.appendChild(componentDOMelement[0])
//compile to the tell angular that render the generated element
//in the js-DOM
$compile(componentDOMelement)($rootScope.$new())
//3rd Building the scene: go to the root location.
$location.url("/")
//Because in the root location exists a http resolution involved
//(the resolve configuration for the "home" state)
$httpBackend.flush()
//Show the html generated
console.log(document.querySelectorAll("body")[0].outerHTML)
}))
//After each test clean the ui-view
afterEach(() => {
treeDOMBody.querySelectorAll("div[ui-view]")[0].remove()
})
it("Should be render a todo list based on the httpResponse", () => {
const todosHTMLNodeList = treeDOMBody.querySelectorAll(".todo-item")
const todosHttpResponseLength = todosHttpResponse.todos.length
expect(todosHTMLNodeList.length).toBe(todosHttpResponseLength)
})
it("Should be delete a todo when a todo item was clicked on the delete button", () => {
let todosHTMLNodeList = treeDOMBody.querySelectorAll(".todo-item")
let targetTodo = todosHTMLNodeList[3]
let todosInitialLenth = todosHTMLNodeList.length
let todosListNewLength
targetTodo.querySelectorAll(".btn-delete-todo")[0].click()
todosHTMLNodeList = treeDOMBody.querySelectorAll(".todo-item")
todosListNewLength = todosHTMLNodeList.length
expect(todosListNewLength).toEqual(todosInitialLenth - 1)
targetTodo = todosHTMLNodeList[0]
targetTodo.querySelectorAll(".btn-delete-todo")[0].click()
todosHTMLNodeList = treeDOMBody.querySelectorAll(".todo-item")
todosListNewLength = todosHTMLNodeList.length
expect(todosListNewLength).toEqual(todosInitialLenth - 2)
})
it("Should be toggle a todo item if the checkbox it's pressed", () => {
let todosHTMLNodeList = treeDOMBody.querySelectorAll(".todo-item")
let targetTodo = todosHTMLNodeList[0]
let targetTodoCheckbox = targetTodo.querySelectorAll("input[type='checkbox']")[0]
let todoInitialCheckedState = targetTodoCheckbox.checked
let todoNewCheckedState
targetTodoCheckbox.click()
todoNewCheckedState = targetTodoCheckbox.checked
expect(todoNewCheckedState).toEqual(!todoInitialCheckedState)
todoInitialCheckedState = todoNewCheckedState
targetTodoCheckbox.click()
todoNewCheckedState = targetTodoCheckbox.checked
expect(todoNewCheckedState).toEqual(!todoInitialCheckedState)
})
})
The HTML render error
TodoListComponent rendering and interaction on '/' base path › Should be toggle a todo item if the checkbox it's pressed
TypeError: Cannot read property 'querySelectorAll' of undefined
at Object.<anonymous> (test/integration/state_home_spec.js:84:44)
TodoListComponent rendering and interaction on '/' base path
✕ Should be render a todo list based on the httpResponse (117ms)
✕ Should be delete a todo when a todo item was clicked on the delete button (25ms)
✕ Should be toggle a todo item if the checkbox it's pressed (28ms)
console.log test/integration/state_home_spec.js:47
<body><!-- uiView: --><div ui-view="" class="ng-scope"></div></body>
console.log test/integration/state_home_spec.js:47
<body><!-- uiView: --><!-- uiView: --><div ui-view="" class="ng-scope"></div></body>
console.log test/integration/state_home_spec.js:47
<body><!-- uiView: --><!-- uiView: --><!-- uiView: --><div ui-view="" class="ng-scope"></div></body>
Expected Behavior:
<body><!-- uiView: --><div ui-view="" class="ng-scope"><todo-list todos-list="::$resolve.todosList" class="ng-scope ng-isolate-scope"><div class="todo-list">
<!-- ngRepeat: todo in $ctrl.todosList track by $index --><div class="todo-item ng-scope" ng-repeat="todo in $ctrl.todosList track by $index">
<label class="ng-binding">
<input type="checkbox" ng-model="todo.completed" class="ng-pristine ng-untouched ng-valid ng-not-empty"> Learn Programming using component based approach
<button class="btn-delete-todo" ng-click="$ctrl.deleteTodo($index)">x</button>
</label>
</div><!-- end ngRepeat: todo in $ctrl.todosList track by $index --><div class="todo-item ng-scope" ng-repeat="todo in $ctrl.todosList track by $index">
<label class="ng-binding">
<input type="checkbox" ng-model="todo.completed" class="ng-pristine ng-untouched ng-valid ng-empty"> Learn Machine Learning
<button class="btn-delete-todo" ng-click="$ctrl.deleteTodo($index)">x</button>
</label>
</div><!-- end ngRepeat: todo in $ctrl.todosList track by $index --><div class="todo-item ng-scope" ng-repeat="todo in $ctrl.todosList track by $index">
<label class="ng-binding">
<input type="checkbox" ng-model="todo.completed" class="ng-pristine ng-untouched ng-valid ng-not-empty"> Finish Medium article
<button class="btn-delete-todo" ng-click="$ctrl.deleteTodo($index)">x</button>
</label>
</div><!-- end ngRepeat: todo in $ctrl.todosList track by $index --><div class="todo-item ng-scope" ng-repeat="todo in $ctrl.todosList track by $index">
<label class="ng-binding">
<input type="checkbox" ng-model="todo.completed" class="ng-pristine ng-untouched ng-valid ng-empty"> Learn to play Jazz music
<button class="btn-delete-todo" ng-click="$ctrl.deleteTodo($index)">x</button>
</label>
</div><!-- end ngRepeat: todo in $ctrl.todosList track by $index --><div class="todo-item ng-scope" ng-repeat="todo in $ctrl.todosList track by $index">
<label class="ng-binding">
<input type="checkbox" ng-model="todo.completed" class="ng-pristine ng-untouched ng-valid ng-empty"> Build a experimental app using google A.I.
<button class="btn-delete-todo" ng-click="$ctrl.deleteTodo($index)">x</button>
</label>
</div><!-- end ngRepeat: todo in $ctrl.todosList track by $index -->
</div>
</todo-list></div></body>
Link to reproduce the issue:
https://github.com/gpincheiraa/angularjs-tdd-jest/tree/async/await-integration-doesnt-work
General Query
-
I have already asked my question on StackOverflow and nobody could answer the question
-
I have already reviewed the sample application for examples of common approaches
-
I believe my question can only be answered by the UI-Router maintainers
gpincheiraa, Temperancia and marcbachmann