Add update client api and dialog (#164)
This commit is contained in:
parent
efcf4ad13d
commit
e32359ed15
|
|
@ -15,6 +15,7 @@ type ClientDatabase interface {
|
||||||
GetClientByID(id uint) *model.Client
|
GetClientByID(id uint) *model.Client
|
||||||
GetClientsByUser(userID uint) []*model.Client
|
GetClientsByUser(userID uint) []*model.Client
|
||||||
DeleteClientByID(id uint) error
|
DeleteClientByID(id uint) error
|
||||||
|
UpdateClient(client *model.Client) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// The ClientAPI provides handlers for managing clients and applications.
|
// The ClientAPI provides handlers for managing clients and applications.
|
||||||
|
|
@ -24,6 +25,65 @@ type ClientAPI struct {
|
||||||
NotifyDeleted func(uint, string)
|
NotifyDeleted func(uint, string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateClient updates a client by its id.
|
||||||
|
// swagger:operation PUT /client/{id} client updateClient
|
||||||
|
//
|
||||||
|
// Update a client.
|
||||||
|
//
|
||||||
|
// ---
|
||||||
|
// consumes: [application/json]
|
||||||
|
// produces: [application/json]
|
||||||
|
// security: [clientTokenHeader: [], clientTokenQuery: [], basicAuth: []]
|
||||||
|
// parameters:
|
||||||
|
// - name: body
|
||||||
|
// in: body
|
||||||
|
// description: the client to update
|
||||||
|
// required: true
|
||||||
|
// schema:
|
||||||
|
// $ref: "#/definitions/Client"
|
||||||
|
// - name: id
|
||||||
|
// in: path
|
||||||
|
// description: the client id
|
||||||
|
// required: true
|
||||||
|
// type: integer
|
||||||
|
// responses:
|
||||||
|
// 200:
|
||||||
|
// description: Ok
|
||||||
|
// schema:
|
||||||
|
// $ref: "#/definitions/Client"
|
||||||
|
// 400:
|
||||||
|
// description: Bad Request
|
||||||
|
// schema:
|
||||||
|
// $ref: "#/definitions/Error"
|
||||||
|
// 401:
|
||||||
|
// description: Unauthorized
|
||||||
|
// schema:
|
||||||
|
// $ref: "#/definitions/Error"
|
||||||
|
// 403:
|
||||||
|
// description: Forbidden
|
||||||
|
// schema:
|
||||||
|
// $ref: "#/definitions/Error"
|
||||||
|
// 404:
|
||||||
|
// description: Not Found
|
||||||
|
// schema:
|
||||||
|
// $ref: "#/definitions/Error"
|
||||||
|
func (a *ClientAPI) UpdateClient(ctx *gin.Context) {
|
||||||
|
withID(ctx, "id", func(id uint) {
|
||||||
|
if client := a.DB.GetClientByID(id); client != nil && client.UserID == auth.GetUserID(ctx) {
|
||||||
|
newValues := &model.Client{}
|
||||||
|
if err := ctx.Bind(newValues); err == nil {
|
||||||
|
client.Name = newValues.Name
|
||||||
|
|
||||||
|
a.DB.UpdateClient(client)
|
||||||
|
|
||||||
|
ctx.JSON(200, client)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ctx.AbortWithError(404, fmt.Errorf("client with id %d doesn't exists", id))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// CreateClient creates a client and returns the access token.
|
// CreateClient creates a client and returns the access token.
|
||||||
// swagger:operation POST /client client createClient
|
// swagger:operation POST /client client createClient
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,40 @@ func (s *ClientSuite) Test_DeleteClient() {
|
||||||
assert.True(s.T(), s.notified)
|
assert.True(s.T(), s.notified)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ClientSuite) Test_UpdateClient_expectSuccess() {
|
||||||
|
s.db.User(5).NewClientWithToken(1, firstClientToken)
|
||||||
|
|
||||||
|
test.WithUser(s.ctx, 5)
|
||||||
|
s.withFormData("name=firefox")
|
||||||
|
s.ctx.Params = gin.Params{{Key: "id", Value: "1"}}
|
||||||
|
s.a.UpdateClient(s.ctx)
|
||||||
|
|
||||||
|
expected := &model.Client{
|
||||||
|
ID: 1,
|
||||||
|
Token: firstClientToken,
|
||||||
|
UserID: 5,
|
||||||
|
Name: "firefox",
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(s.T(), 200, s.recorder.Code)
|
||||||
|
assert.Equal(s.T(), expected, s.db.GetClientByID(1))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ClientSuite) Test_UpdateClient_expectNotFound() {
|
||||||
|
test.WithUser(s.ctx, 5)
|
||||||
|
s.ctx.Params = gin.Params{{Key: "id", Value: "2"}}
|
||||||
|
s.a.UpdateClient(s.ctx)
|
||||||
|
|
||||||
|
assert.Equal(s.T(), 404, s.recorder.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ClientSuite) Test_UpdateClient_WithMissingAttributes_expectBadRequest() {
|
||||||
|
test.WithUser(s.ctx, 5)
|
||||||
|
s.a.UpdateClient(s.ctx)
|
||||||
|
|
||||||
|
assert.Equal(s.T(), 400, s.recorder.Code)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *ClientSuite) withFormData(formData string) {
|
func (s *ClientSuite) withFormData(formData string) {
|
||||||
s.ctx.Request = httptest.NewRequest("POST", "/token", strings.NewReader(formData))
|
s.ctx.Request = httptest.NewRequest("POST", "/token", strings.NewReader(formData))
|
||||||
s.ctx.Request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
s.ctx.Request.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
|
|
||||||
|
|
@ -38,3 +38,8 @@ func (d *GormDatabase) GetClientsByUser(userID uint) []*model.Client {
|
||||||
func (d *GormDatabase) DeleteClientByID(id uint) error {
|
func (d *GormDatabase) DeleteClientByID(id uint) error {
|
||||||
return d.DB.Where("id = ?", id).Delete(&model.Client{}).Error
|
return d.DB.Where("id = ?", id).Delete(&model.Client{}).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UpdateClient updates a client.
|
||||||
|
func (d *GormDatabase) UpdateClient(client *model.Client) error {
|
||||||
|
return d.DB.Save(client).Error
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,11 @@ func (s *DatabaseSuite) TestClient() {
|
||||||
newClient = s.db.GetClientByToken(client.Token)
|
newClient = s.db.GetClientByToken(client.Token)
|
||||||
assert.Equal(s.T(), client, newClient)
|
assert.Equal(s.T(), client, newClient)
|
||||||
|
|
||||||
|
updateClient := &model.Client{ID: client.ID, UserID: user.ID, Token: "C0000000000", Name: "new_name"}
|
||||||
|
s.db.UpdateClient(updateClient)
|
||||||
|
updatedClient := s.db.GetClientByID(client.ID)
|
||||||
|
assert.Equal(s.T(), updateClient, updatedClient)
|
||||||
|
|
||||||
s.db.DeleteClientByID(client.ID)
|
s.db.DeleteClientByID(client.ID)
|
||||||
|
|
||||||
clients = s.db.GetClientsByUser(user.ID)
|
clients = s.db.GetClientsByUser(user.ID)
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
//
|
//
|
||||||
// Schemes: http, https
|
// Schemes: http, https
|
||||||
// Host: localhost
|
// Host: localhost
|
||||||
// Version: 2.0.0
|
// Version: 2.0.1
|
||||||
// License: MIT https://github.com/gotify/server/blob/master/LICENSE
|
// License: MIT https://github.com/gotify/server/blob/master/LICENSE
|
||||||
//
|
//
|
||||||
// Consumes:
|
// Consumes:
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
"name": "MIT",
|
"name": "MIT",
|
||||||
"url": "https://github.com/gotify/server/blob/master/LICENSE"
|
"url": "https://github.com/gotify/server/blob/master/LICENSE"
|
||||||
},
|
},
|
||||||
"version": "2.0.0"
|
"version": "2.0.1"
|
||||||
},
|
},
|
||||||
"host": "localhost",
|
"host": "localhost",
|
||||||
"paths": {
|
"paths": {
|
||||||
|
|
@ -599,6 +599,80 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/client/{id}": {
|
"/client/{id}": {
|
||||||
|
"put": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"clientTokenHeader": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"clientTokenQuery": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"basicAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"client"
|
||||||
|
],
|
||||||
|
"summary": "Update a client.",
|
||||||
|
"operationId": "updateClient",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "the client to update",
|
||||||
|
"name": "body",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Client"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "integer",
|
||||||
|
"description": "the client id",
|
||||||
|
"name": "id",
|
||||||
|
"in": "path",
|
||||||
|
"required": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Ok",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Client"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Unauthorized",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
"description": "Forbidden",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"404": {
|
||||||
|
"description": "Not Found",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/Error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -139,6 +139,8 @@ func Create(db *database.GormDatabase, vInfo *model.VersionInfo, conf *config.Co
|
||||||
client.POST("", clientHandler.CreateClient)
|
client.POST("", clientHandler.CreateClient)
|
||||||
|
|
||||||
client.DELETE("/:id", clientHandler.DeleteClient)
|
client.DELETE("/:id", clientHandler.DeleteClient)
|
||||||
|
|
||||||
|
client.PUT("/:id", clientHandler.UpdateClient)
|
||||||
}
|
}
|
||||||
|
|
||||||
message := clientAuth.Group("/message")
|
message := clientAuth.Group("/message")
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,13 @@ export class ClientStore extends BaseStore<IClient> {
|
||||||
.then(() => this.snack('Client deleted'));
|
.then(() => this.snack('Client deleted'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
public update = async (id: number, name: string): Promise<void> => {
|
||||||
|
await axios.put(`${config.get('url')}client/${id}`, {name});
|
||||||
|
await this.refresh();
|
||||||
|
this.snack('Client updated');
|
||||||
|
};
|
||||||
|
|
||||||
@action
|
@action
|
||||||
public createNoNotifcation = async (name: string): Promise<IClient> => {
|
public createNoNotifcation = async (name: string): Promise<IClient> => {
|
||||||
const client = await axios.post(`${config.get('url')}client`, {name});
|
const client = await axios.post(`${config.get('url')}client`, {name});
|
||||||
|
|
|
||||||
|
|
@ -7,11 +7,13 @@ import TableCell from '@material-ui/core/TableCell';
|
||||||
import TableHead from '@material-ui/core/TableHead';
|
import TableHead from '@material-ui/core/TableHead';
|
||||||
import TableRow from '@material-ui/core/TableRow';
|
import TableRow from '@material-ui/core/TableRow';
|
||||||
import Delete from '@material-ui/icons/Delete';
|
import Delete from '@material-ui/icons/Delete';
|
||||||
|
import Edit from '@material-ui/icons/Edit';
|
||||||
import React, {Component, SFC} from 'react';
|
import React, {Component, SFC} from 'react';
|
||||||
import ConfirmDialog from '../common/ConfirmDialog';
|
import ConfirmDialog from '../common/ConfirmDialog';
|
||||||
import DefaultPage from '../common/DefaultPage';
|
import DefaultPage from '../common/DefaultPage';
|
||||||
import ToggleVisibility from '../common/ToggleVisibility';
|
import ToggleVisibility from '../common/ToggleVisibility';
|
||||||
import AddClientDialog from './AddClientDialog';
|
import AddClientDialog from './AddClientDialog';
|
||||||
|
import UpdateDialog from './UpdateClientDialog';
|
||||||
import {observer} from 'mobx-react';
|
import {observer} from 'mobx-react';
|
||||||
import {observable} from 'mobx';
|
import {observable} from 'mobx';
|
||||||
import {inject, Stores} from '../inject';
|
import {inject, Stores} from '../inject';
|
||||||
|
|
@ -22,12 +24,15 @@ class Clients extends Component<Stores<'clientStore'>> {
|
||||||
private showDialog = false;
|
private showDialog = false;
|
||||||
@observable
|
@observable
|
||||||
private deleteId: false | number = false;
|
private deleteId: false | number = false;
|
||||||
|
@observable
|
||||||
|
private updateId: false | number = false;
|
||||||
|
|
||||||
public componentDidMount = () => this.props.clientStore.refresh();
|
public componentDidMount = () => this.props.clientStore.refresh();
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const {
|
const {
|
||||||
deleteId,
|
deleteId,
|
||||||
|
updateId,
|
||||||
showDialog,
|
showDialog,
|
||||||
props: {clientStore},
|
props: {clientStore},
|
||||||
} = this;
|
} = this;
|
||||||
|
|
@ -47,6 +52,7 @@ class Clients extends Component<Stores<'clientStore'>> {
|
||||||
<TableCell>Name</TableCell>
|
<TableCell>Name</TableCell>
|
||||||
<TableCell style={{width: 200}}>token</TableCell>
|
<TableCell style={{width: 200}}>token</TableCell>
|
||||||
<TableCell />
|
<TableCell />
|
||||||
|
<TableCell />
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
|
|
@ -56,6 +62,7 @@ class Clients extends Component<Stores<'clientStore'>> {
|
||||||
key={client.id}
|
key={client.id}
|
||||||
name={client.name}
|
name={client.name}
|
||||||
value={client.token}
|
value={client.token}
|
||||||
|
fEdit={() => (this.updateId = client.id)}
|
||||||
fDelete={() => (this.deleteId = client.id)}
|
fDelete={() => (this.deleteId = client.id)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
@ -70,6 +77,13 @@ class Clients extends Component<Stores<'clientStore'>> {
|
||||||
fOnSubmit={clientStore.create}
|
fOnSubmit={clientStore.create}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{updateId !== false && (
|
||||||
|
<UpdateDialog
|
||||||
|
fClose={() => (this.updateId = false)}
|
||||||
|
fOnSubmit={(name) => clientStore.update(updateId, name)}
|
||||||
|
initialName={clientStore.getByID(updateId).name}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{deleteId !== false && (
|
{deleteId !== false && (
|
||||||
<ConfirmDialog
|
<ConfirmDialog
|
||||||
title="Confirm Delete"
|
title="Confirm Delete"
|
||||||
|
|
@ -86,10 +100,11 @@ class Clients extends Component<Stores<'clientStore'>> {
|
||||||
interface IRowProps {
|
interface IRowProps {
|
||||||
name: string;
|
name: string;
|
||||||
value: string;
|
value: string;
|
||||||
|
fEdit: VoidFunction;
|
||||||
fDelete: VoidFunction;
|
fDelete: VoidFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Row: SFC<IRowProps> = ({name, value, fDelete}) => (
|
const Row: SFC<IRowProps> = ({name, value, fEdit, fDelete}) => (
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell>{name}</TableCell>
|
<TableCell>{name}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
|
|
@ -99,6 +114,11 @@ const Row: SFC<IRowProps> = ({name, value, fDelete}) => (
|
||||||
/>
|
/>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell numeric padding="none">
|
<TableCell numeric padding="none">
|
||||||
|
<IconButton onClick={fEdit} className="edit">
|
||||||
|
<Edit />
|
||||||
|
</IconButton>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell>
|
||||||
<IconButton onClick={fDelete} className="delete">
|
<IconButton onClick={fDelete} className="delete">
|
||||||
<Delete />
|
<Delete />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
import Button from '@material-ui/core/Button';
|
||||||
|
import Dialog from '@material-ui/core/Dialog';
|
||||||
|
import DialogActions from '@material-ui/core/DialogActions';
|
||||||
|
import DialogContent from '@material-ui/core/DialogContent';
|
||||||
|
import DialogContentText from '@material-ui/core/DialogContentText';
|
||||||
|
import DialogTitle from '@material-ui/core/DialogTitle';
|
||||||
|
import TextField from '@material-ui/core/TextField';
|
||||||
|
import Tooltip from '@material-ui/core/Tooltip';
|
||||||
|
import React, {Component} from 'react';
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
fClose: VoidFunction;
|
||||||
|
fOnSubmit: (name: string) => void;
|
||||||
|
initialName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class UpdateDialog extends Component<IProps, IState> {
|
||||||
|
public state = {name: ''};
|
||||||
|
|
||||||
|
public componentWillMount() {
|
||||||
|
this.setState({name: this.props.initialName});
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
const {fClose, fOnSubmit} = this.props;
|
||||||
|
const {name} = this.state;
|
||||||
|
const submitEnabled = this.state.name.length !== 0;
|
||||||
|
const submitAndClose = () => {
|
||||||
|
fOnSubmit(name);
|
||||||
|
fClose();
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
open={true}
|
||||||
|
onClose={fClose}
|
||||||
|
aria-labelledby="form-dialog-title"
|
||||||
|
id="client-dialog">
|
||||||
|
<DialogTitle id="form-dialog-title">Update a Client</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<DialogContentText>
|
||||||
|
A client manages messages, clients, applications and users (with admin
|
||||||
|
permissions).
|
||||||
|
</DialogContentText>
|
||||||
|
<TextField
|
||||||
|
autoFocus
|
||||||
|
margin="dense"
|
||||||
|
className="name"
|
||||||
|
label="Name *"
|
||||||
|
type="text"
|
||||||
|
value={name}
|
||||||
|
onChange={this.handleChange.bind(this, 'name')}
|
||||||
|
fullWidth
|
||||||
|
/>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={fClose}>Cancel</Button>
|
||||||
|
<Tooltip title={submitEnabled ? '' : 'name is required'}>
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
className="update"
|
||||||
|
disabled={!submitEnabled}
|
||||||
|
onClick={submitAndClose}
|
||||||
|
color="primary"
|
||||||
|
variant="raised">
|
||||||
|
Update
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleChange(propertyName: string, event: React.ChangeEvent<HTMLInputElement>) {
|
||||||
|
const state = {};
|
||||||
|
state[propertyName] = event.target.value;
|
||||||
|
this.setState(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import {Page} from 'puppeteer';
|
import {Page} from 'puppeteer';
|
||||||
import {newTest, GotifyTest} from './setup';
|
import {newTest, GotifyTest} from './setup';
|
||||||
import {count, innerText, waitForExists, waitToDisappear} from './utils';
|
import {count, innerText, waitForExists, waitToDisappear, clearField} from './utils';
|
||||||
import * as auth from './authentication';
|
import * as auth from './authentication';
|
||||||
|
|
||||||
import * as selector from './selector';
|
import * as selector from './selector';
|
||||||
|
|
@ -17,9 +17,30 @@ afterAll(async () => await gotify.close());
|
||||||
enum Col {
|
enum Col {
|
||||||
Name = 1,
|
Name = 1,
|
||||||
Token = 2,
|
Token = 2,
|
||||||
Delete = 3,
|
Edit = 3,
|
||||||
|
Delete = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const hasClient = (name: string, row: number): (() => Promise<void>) => {
|
||||||
|
return async () => {
|
||||||
|
expect(await innerText(page, $table.cell(row, Col.Name))).toBe(name);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateClient = (id: number, data: {name?: string}): (() => Promise<void>) => {
|
||||||
|
return async () => {
|
||||||
|
await page.click($table.cell(id, Col.Edit, '.edit'));
|
||||||
|
await page.waitForSelector($dialog.selector());
|
||||||
|
if (data.name) {
|
||||||
|
const nameSelector = $dialog.input('.name');
|
||||||
|
await clearField(page, nameSelector);
|
||||||
|
await page.type(nameSelector, data.name);
|
||||||
|
}
|
||||||
|
await page.click($dialog.button('.update'));
|
||||||
|
await waitToDisappear(page, $dialog.selector());
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
const $table = selector.table('#client-table');
|
const $table = selector.table('#client-table');
|
||||||
const $dialog = selector.form('#client-dialog');
|
const $dialog = selector.form('#client-dialog');
|
||||||
|
|
||||||
|
|
@ -56,6 +77,8 @@ describe('Client', () => {
|
||||||
expect(await innerText(page, $table.cell(2, Col.Name))).toBe('phone');
|
expect(await innerText(page, $table.cell(2, Col.Name))).toBe('phone');
|
||||||
expect(await innerText(page, $table.cell(3, Col.Name))).toBe('desktop app');
|
expect(await innerText(page, $table.cell(3, Col.Name))).toBe('desktop app');
|
||||||
});
|
});
|
||||||
|
it('updates client', updateClient(1, {name: 'firefox'}));
|
||||||
|
it('has updated client name', hasClient('firefox', 1));
|
||||||
it('shows token', async () => {
|
it('shows token', async () => {
|
||||||
await page.click($table.cell(3, Col.Token, '.toggle-visibility'));
|
await page.click($table.cell(3, Col.Token, '.toggle-visibility'));
|
||||||
expect((await innerText(page, $table.cell(3, Col.Token))).startsWith('C')).toBeTruthy();
|
expect((await innerText(page, $table.cell(3, Col.Token))).startsWith('C')).toBeTruthy();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue