Added control page tests and fixed bugs
This commit is contained in:
parent
fe33c8d042
commit
e32f12019e
@ -15,11 +15,6 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="container-md">
|
<div class="container-md">
|
||||||
|
|
||||||
<div class="new-section">
|
|
||||||
<p class="row page-description" id="licences_remaining">Свободных Мест:</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% for message in messages %}
|
{% for message in messages %}
|
||||||
<script>create_notification('{{message}}','','{{message.tags}}',2000)</script>
|
<script>create_notification('{{message}}','','{{message.tags}}',2000)</script>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@ -27,75 +22,15 @@
|
|||||||
{% block form %}
|
{% block form %}
|
||||||
<form method="post">
|
<form method="post">
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
|
|
||||||
<div class="row justify-content-center new-section">
|
<div class="row justify-content-center new-section">
|
||||||
|
|
||||||
<div class="col-10">
|
<div class="col-10">
|
||||||
<h6 class="table-title">Список сотрудников</h6>
|
<h6 class="table-title">Список сотрудников</h6>
|
||||||
|
|
||||||
{% block table %}
|
{% block table %}
|
||||||
<table class="table table-dark light-table">
|
<div id="table"></div>
|
||||||
|
|
||||||
<thead>
|
|
||||||
<th>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
class="form-check-input"
|
|
||||||
id="head-checkbox"
|
|
||||||
/>
|
|
||||||
</th>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Email</th>
|
|
||||||
<th>Role</th>
|
|
||||||
</thead>
|
|
||||||
<tbody id="tbody"></tbody>
|
|
||||||
|
|
||||||
</table>
|
|
||||||
<p id="loading">Данные загружаются...</p>
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% block count %}
|
|
||||||
<div class="row justify-content-center new-section">
|
|
||||||
<div class="col-5">
|
|
||||||
<div class="info">
|
|
||||||
|
|
||||||
<div class="info-row">
|
|
||||||
<div class="info-target">Инженеров:</div>
|
|
||||||
<div class="info-quantity">
|
|
||||||
<div class="status-circle-small light-green"></div>
|
|
||||||
<span class="info-quantity-value">{{ engineers }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="info-row">
|
|
||||||
<div class="info-target">Легких агентов:</div>
|
|
||||||
<div class="info-quantity">
|
|
||||||
<div class="status-circle-small light-yellow"></div>
|
|
||||||
<span class="info-quantity-value">{{ light_agents }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block buttons %}
|
|
||||||
<div class="col-5">
|
|
||||||
|
|
||||||
<button type="submit" name="engineer" class="request-acess-button default-button">
|
|
||||||
Назначить выбранных на роль инженера
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button type="submit" name="light_agent" class="hand-over-acess-button default-button">
|
|
||||||
Назначить выбранных на роль легкого агента
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</form>
|
</form>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
@ -1,95 +1,84 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import {render, unmountComponentAtNode} from "react-dom";
|
import {render, unmountComponentAtNode} from "react-dom";
|
||||||
import {act} from "react-dom/test-utils";
|
import {act} from "react-dom/test-utils";
|
||||||
import {TableBody} from "../src/control";
|
import {Table} from "../src/control";
|
||||||
import * as test_data from "./test_users.json"
|
import * as test_data from "./test_users.json"
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import MockAdapter from "axios-mock-adapter";
|
||||||
|
|
||||||
|
let mock;
|
||||||
let container = null
|
let container = null
|
||||||
let table = null
|
|
||||||
let load = null
|
|
||||||
let engineer_count = null
|
|
||||||
let agents_count = null
|
|
||||||
let licences_remaining = null
|
|
||||||
jest.mock("axios", () => {
|
|
||||||
return {
|
|
||||||
get: jest.fn(() => Promise.resolve())
|
|
||||||
};
|
|
||||||
});
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
table = document.createElement("table");
|
mock = new MockAdapter(axios);
|
||||||
container = document.createElement("tbody");
|
mock.onGet('/api/users').reply(200, test_data)
|
||||||
container.id = "tbody";
|
container = document.createElement('div')
|
||||||
table.appendChild(container);
|
container.id = "table"
|
||||||
load = document.createElement("p");
|
document.body.appendChild(container)
|
||||||
load.id = "loading"
|
})
|
||||||
load.innerHTML = "Данные загружаются";
|
|
||||||
licences_remaining = document.createElement('p')
|
|
||||||
licences_remaining.id = "licences_remaining"
|
|
||||||
engineer_count = document.createElement("p")
|
|
||||||
agents_count = document.createElement("p")
|
|
||||||
engineer_count.className = "info-quantity-value"
|
|
||||||
agents_count.className = "info-quantity-value"
|
|
||||||
document.body.appendChild(table)
|
|
||||||
document.body.appendChild(engineer_count)
|
|
||||||
document.body.appendChild(agents_count)
|
|
||||||
document.body.appendChild(licences_remaining)
|
|
||||||
document.body.appendChild(load)
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
unmountComponentAtNode(container);
|
unmountComponentAtNode(container);
|
||||||
|
mock.restore()
|
||||||
container.remove();
|
container.remove();
|
||||||
table.remove();
|
|
||||||
engineer_count.remove()
|
|
||||||
agents_count.remove()
|
|
||||||
licences_remaining.remove()
|
|
||||||
container = null;
|
container = null;
|
||||||
table = null;
|
|
||||||
load = null;
|
|
||||||
engineer_count = null
|
|
||||||
agents_count = null
|
|
||||||
licences_remaining = null
|
|
||||||
});
|
});
|
||||||
describe("testing table", (done) => {
|
|
||||||
it("has only main table row without axios request", () => {
|
it("has only main table row without axios request", () => {
|
||||||
act(() => {
|
act(() => {
|
||||||
render(<TableBody/>, container);
|
render(<Table/>, container);
|
||||||
});
|
});
|
||||||
expect(container.getElementsByTagName("tr").length).toBe(1);
|
let tbody = container.querySelector("#tbody")
|
||||||
|
expect(tbody.getElementsByTagName('tr').length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("shows valid number of free workplaces", async () => {
|
it("shows valid number of free workplaces", async () => {
|
||||||
axios.get.mockImplementation(() => Promise.resolve({data: test_data}));
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
render(<TableBody/>, container)
|
render(<Table/>, container)
|
||||||
})
|
})
|
||||||
let licences = Number(licences_remaining.textContent.replace(/Свободных мест: /, ''))
|
let element = container.querySelector('#licences_remaining')
|
||||||
|
let licences = Number(element.innerHTML.replace(/Свободных мест: /, ''))
|
||||||
expect(licences).toEqual(1)
|
expect(licences).toEqual(1)
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Pretext must be deleted on render", () => {
|
it("Pretext must be deleted on render", () => {
|
||||||
act(() => {
|
act(() => {
|
||||||
render(<TableBody/>, container)
|
render(<Table/>, container)
|
||||||
})
|
})
|
||||||
expect(document.body).not.toContain(load)
|
expect(document.body).not.toContain(container.querySelector('#loading'))
|
||||||
});
|
});
|
||||||
|
|
||||||
it("has valid number of table rows with axios request", async () => {
|
it("has valid number of table rows with axios request", async () => {
|
||||||
axios.get.mockImplementation(() => Promise.resolve({data: test_data}));
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
render(<TableBody/>, container)
|
render(<Table/>, container)
|
||||||
})
|
})
|
||||||
expect(container.getElementsByTagName("tr").length)
|
let tbody = container.querySelector("#tbody")
|
||||||
.toEqual(test_data.users.length + test_data.zendesk_users.length + 1)
|
expect(tbody.getElementsByTagName('tr').length)
|
||||||
|
.toEqual(test_data.users.length + test_data.zendesk_users.length)
|
||||||
});
|
});
|
||||||
|
|
||||||
it("show valid number for engineers and light agents", async () => {
|
it("show valid number for engineers and light agents", async () => {
|
||||||
axios.get.mockImplementation(() => Promise.resolve({data: test_data}));
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
render(<TableBody/>, container)
|
render(<Table/>, container)
|
||||||
})
|
})
|
||||||
expect(Number(engineer_count.textContent)).toEqual(test_data.engineers)
|
let engineers = container.querySelector('#engineers')
|
||||||
expect(Number(agents_count.textContent)).toEqual(test_data.light_agents)
|
let agents = container.querySelector('#agents')
|
||||||
|
expect(Number(engineers.textContent)).toEqual(test_data.engineers)
|
||||||
|
expect(Number(agents.textContent)).toEqual(test_data.light_agents)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("called one request on mount", async () => {
|
||||||
|
let req = jest.spyOn(Table.prototype, "get_users")
|
||||||
|
await act(async () => {
|
||||||
|
render(<Table/>, container)
|
||||||
|
})
|
||||||
|
expect(req).toHaveBeenCalledTimes(1)
|
||||||
|
})
|
||||||
|
it("checkbox count equals users from db count", async () => {
|
||||||
|
await act(async () => {
|
||||||
|
render(<Table/>, container)
|
||||||
|
})
|
||||||
|
let tbody = container.querySelector("#tbody")
|
||||||
|
let checkboxes = tbody.querySelectorAll("input[type='checkbox']")
|
||||||
|
let users = test_data.users
|
||||||
|
expect(checkboxes.length).toEqual(users.length)
|
||||||
})
|
})
|
||||||
|
@ -3,9 +3,6 @@ module.exports = {
|
|||||||
testPathIgnorePatterns: [
|
testPathIgnorePatterns: [
|
||||||
"./node_modules/"
|
"./node_modules/"
|
||||||
],
|
],
|
||||||
unmockedModulePathPatterns: [
|
|
||||||
"./node_modules/react"
|
|
||||||
],
|
|
||||||
roots: [
|
roots: [
|
||||||
"./__tests__"
|
"./__tests__"
|
||||||
],
|
],
|
||||||
|
@ -1,6 +1,48 @@
|
|||||||
import React from "react";
|
import React, {useState} from "react";
|
||||||
import ReactDOM from "react-dom";
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import * as ReactDOM from "react-dom";
|
||||||
|
|
||||||
|
function FreeWorkplaces(props) {
|
||||||
|
return (
|
||||||
|
<div className="new-section">
|
||||||
|
<p className="row page-description" id="licences_remaining">Свободных мест: {props.count}</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function WorkersCount(props) {
|
||||||
|
return (
|
||||||
|
<div className="row justify-content-center new-section d-flex align-items-center">
|
||||||
|
<div className="col-5">
|
||||||
|
<div className="info">
|
||||||
|
<div className="info-row">
|
||||||
|
<div className="info-target">Инженеров:</div>
|
||||||
|
<div className="info-quantity">
|
||||||
|
<div className="status-circle-small light-green"></div>
|
||||||
|
<span className="info-quantity-value" id="engineers">{props.engineers}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="info-row">
|
||||||
|
<div className="info-target">Легких агентов:</div>
|
||||||
|
<div className="info-quantity">
|
||||||
|
<div className="status-circle-small light-yellow"></div>
|
||||||
|
<span className="info-quantity-value" id="agents">{props.light_agents}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-5">
|
||||||
|
<button type="submit" name="engineer" className="request-acess-button default-button">
|
||||||
|
Назначить выбранных на роль инженера
|
||||||
|
</button>
|
||||||
|
<button type="submit" name="light_agent" className="hand-over-acess-button default-button">
|
||||||
|
Назначить выбранных на роль легкого агента
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
class ModelUserTableRow extends React.Component {
|
class ModelUserTableRow extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
@ -26,11 +68,10 @@ class ModelUserTableRow extends React.Component {
|
|||||||
|
|
||||||
class ModelUserTableRows extends React.Component {
|
class ModelUserTableRows extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return ReactDOM.createPortal(
|
return (
|
||||||
this.props.users.map((user, key) => (
|
this.props.users.map((user, key) => (
|
||||||
<ModelUserTableRow user={user} key={key} />
|
<ModelUserTableRow user={user} key={key} />
|
||||||
)),
|
))
|
||||||
document.getElementById("tbody")
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,39 +99,27 @@ class ZendeskUserTableRow extends React.Component {
|
|||||||
|
|
||||||
class ZendeskUserTableRows extends React.Component {
|
class ZendeskUserTableRows extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return ReactDOM.createPortal(
|
return (
|
||||||
this.props.users.map((user, key) => (
|
this.props.users.map((user, key) => (
|
||||||
<ZendeskUserTableRow user={user} key={key} />
|
<ZendeskUserTableRow user={user} key={key} />
|
||||||
)),
|
))
|
||||||
document.getElementById("tbody")
|
)
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TableBody extends React.Component {
|
export class Table extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
users: [],
|
users: [],
|
||||||
engineers: 0,
|
engineers: null,
|
||||||
light_agents: 0,
|
light_agents: null,
|
||||||
zendesk_users: [],
|
zendesk_users: [],
|
||||||
max_agents: 3,
|
max_agents: null,
|
||||||
|
renderLoad: true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
change_elements_html() {
|
|
||||||
let elements = document.querySelectorAll(".info-quantity-value");
|
|
||||||
let licences = document.getElementById("licences_remaining");
|
|
||||||
elements[0].innerHTML = this.state.engineers;
|
|
||||||
elements[1].innerHTML = this.state.light_agents;
|
|
||||||
let max_licences = Math.max(
|
|
||||||
this.state.max_agents - this.state.engineers,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
licences.innerHTML = "Свободных мест: " + max_licences;
|
|
||||||
}
|
|
||||||
|
|
||||||
async get_users() {
|
async get_users() {
|
||||||
await axios.get("/api/users").then((response) => {
|
await axios.get("/api/users").then((response) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
@ -99,19 +128,23 @@ export class TableBody extends React.Component {
|
|||||||
light_agents: response.data.light_agents,
|
light_agents: response.data.light_agents,
|
||||||
zendesk_users: response.data.zendesk_users,
|
zendesk_users: response.data.zendesk_users,
|
||||||
max_agents: response.data.max_agents,
|
max_agents: response.data.max_agents,
|
||||||
|
renderLoad: false
|
||||||
});
|
});
|
||||||
|
return response
|
||||||
|
}).catch(reason => {
|
||||||
|
console.log(reason)
|
||||||
});
|
});
|
||||||
this.change_elements_html();
|
|
||||||
}
|
|
||||||
|
|
||||||
delete_pretext() {
|
|
||||||
document.getElementById("loading").remove();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.get_users().then(() => this.delete_pretext());
|
this.get_users().then(() => {})
|
||||||
|
.catch(reason => {
|
||||||
|
console.log(reason)
|
||||||
|
});
|
||||||
this.interval = setInterval(() => {
|
this.interval = setInterval(() => {
|
||||||
this.get_users();
|
this.get_users().catch(reason => {
|
||||||
|
console.log(reason)
|
||||||
|
})
|
||||||
}, 60000);
|
}, 60000);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,10 +154,31 @@ export class TableBody extends React.Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
|
<div>
|
||||||
|
<FreeWorkplaces count={Math.max(this.state.max_agents - this.state.engineers, 0)}/>
|
||||||
|
<table className="table table-dark light-table">
|
||||||
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
|
<th>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
className="form-check-input"
|
||||||
|
id="head-checkbox"
|
||||||
|
/>
|
||||||
|
</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Email</th>
|
||||||
|
<th>Role</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="tbody">
|
||||||
<ModelUserTableRows users={this.state.users}/>
|
<ModelUserTableRows users={this.state.users}/>
|
||||||
<ZendeskUserTableRows users={this.state.zendesk_users}/>
|
<ZendeskUserTableRows users={this.state.zendesk_users}/>
|
||||||
</tr>
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{this.state.renderLoad === true ? <p id="loading">Данные загружаются...</p> : null}
|
||||||
|
<WorkersCount engineers={this.state.engineers} light_agents={this.state.light_agents}/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {TableBody} from "./control"
|
import {Table} from "./control"
|
||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
@ -12,5 +12,5 @@ function head_checkbox() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ReactDOM.render(<TableBody />, document.getElementById("tbody"));
|
ReactDOM.render(<Table />, document.getElementById("table"));
|
||||||
head_checkbox();
|
head_checkbox();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user