Solution to Challenge 2 - Data Grid Validation and CRUD Operations
Solution to Challenge 2 - Data Grid Validation and CRUD Operations
挑战 2 解决方案 - 数据网格验证与 CRUD 操作
Challenge #2 is done — here’s my solution to Challenge 2 - Data Grid Validation and CRUD Operations. 挑战 2 已完成——以下是我针对“数据网格验证与 CRUD 操作”挑战的解决方案。
First, the gaps in the user story:
- The delete option didn’t include a confirmation dialog before deleting.
- The translations for: confirmation dialog title, message, and buttons are not in the attached CSV with all the translations; error messages for invalid server data; empty state of the grid after filtering; success message.
- Behavior for authenticated non-admin users isn’t defined (403 page? menu item hidden? redirect?). 首先,用户故事中存在的缺失项:
- 删除选项在执行前缺少确认对话框。
- 缺少以下内容的翻译:确认对话框的标题、消息和按钮(未包含在附带的 CSV 翻译文件中);无效服务器数据的错误消息;过滤后网格的空状态;成功提示消息。
- 已认证但非管理员用户的行为未定义(显示 403 页面?隐藏菜单项?还是重定向?)。
The bugs that were fixed now:
- Error 500 with duplicated Id: If you call the POST api/server with a duplicated Id (internal id not visible on the UI) you got a 500 error; if the API is used for third-party companies, they couldn’t know if the Id is used or not.
- Error message isn’t clear: for example, for a name that is longer than 151 characters, it only said “StringLength”, but the consumer of the API couldn’t understand what is wrong.
- Error message in English: The user selected German, but error messages like “duplicated server key” were in English. The fix to the bugs was to add a header on the request with the user-selected language
X-UI-Lang; with this header, you can get the error messages in different languages. 目前已修复的 Bug: - 重复 ID 导致的 500 错误:如果使用重复 ID(UI 上不可见的内部 ID)调用
POST api/server,会收到 500 错误;如果第三方公司使用该 API,他们无法判断 ID 是否已被占用。 - 错误消息不明确:例如,当名称超过 151 个字符时,仅显示“StringLength”,API 调用者无法理解具体错误原因。
- 错误消息为英文:用户选择了德语,但诸如“duplicated server key”之类的错误消息仍显示为英文。修复方法是在请求中添加一个用户所选语言的请求头
X-UI-Lang,通过该请求头即可获取对应语言的错误消息。
API Testing: In general, I created the tests:
Servers_WithAdminUser_ReturnsServers: Test theGET api/Serverto check that it returns at least one server and validate the JSON schema on the response.Servers_withNormalUser_Returns403: Test theGET api/Serverto check that it returns Forbidden (403) when the user is not an admin.Servers_withoutJwt_Returns401: Test theGET api/Serverwithout a JWT token returns 401. API 测试: 总体而言,我创建了以下测试:Servers_WithAdminUser_ReturnsServers:测试GET api/Server,检查是否至少返回一个服务器,并验证响应的 JSON 模式。Servers_withNormalUser_Returns403:测试GET api/Server,检查非管理员用户访问时是否返回禁止访问 (403)。Servers_withoutJwt_Returns401:测试在没有 JWT 令牌的情况下访问GET api/Server是否返回 401。
In some projects, this validation was part of integration tests by developers and not by the QA. So I only created one as an example, but you can also create them for the other POST/PUT/DELETE methods. 在某些项目中,此类验证属于开发人员进行的集成测试,而非 QA 测试。因此我仅创建了一个示例,但你也可以为其他 POST/PUT/DELETE 方法创建类似的测试。
Servers_WithValidServerInfo_CreatesAServer: I tested thePOST api/Serverwith valid random data and checked the response returns the same info.Server_WithValidKey_ReturnsServerInfo:GET api/Server/:serverKeyto test that it returns the info for the created server. You can include this also in the previous test, but I prefer to add another test case.Server_WithInValidKey_Returns404:GET api/Server/0(0 is an invalid key due to the min value being 1) returns 404; sometimes instead of 404, some APIs return 200 with an empty value.Servers_WithInvalidInfo_ReturnsError: I tested with a duplicated key, missing required fields, and a name with more than the maximum length (151) characters, and I tested that the error message is clear and translated to the user’s language via the request header.Servers_WithValidServerInfo_UpdatesAServer:PUT api/Server/:serverKeywith valid info returns status code 204 (No content).Servers_WithInvalidServerId_returns400Error: Test with an invalid key, or invalid JSON like a string instead of a number.Servers_WithValidServerId_DeletesCorrectly: Test theDELETE api/Server/:serverIdwith the created serverId will delete the created server.Servers_WithInValidServerId_Returns404: Test theDELETE api/Server/:serverIdwith an invalid serverId like 0 should return 404.Servers_WithValidServerInfo_CreatesAServer:使用有效的随机数据测试POST api/Server,并检查响应是否返回相同信息。Server_WithValidKey_ReturnsServerInfo:测试GET api/Server/:serverKey,确保返回所创建服务器的信息。你可以将其包含在之前的测试中,但我更倾向于单独增加一个测试用例。Server_WithInValidKey_Returns404:测试GET api/Server/0(0 是无效键,因为最小值是 1)返回 404;有时某些 API 不会返回 404,而是返回 200 和空值。Servers_WithInvalidInfo_ReturnsError:测试了重复键、缺少必填字段以及名称超过最大长度(151)的情况,并验证了错误消息是否清晰,且通过请求头翻译成了用户语言。Servers_WithValidServerInfo_UpdatesAServer:使用有效信息测试PUT api/Server/:serverKey,返回状态码 204 (No content)。Servers_WithInvalidServerId_returns400Error:测试无效键,或无效的 JSON(例如将数字写成字符串)。Servers_WithValidServerId_DeletesCorrectly:测试DELETE api/Server/:serverId,确保使用创建的 serverId 可以正确删除服务器。Servers_WithInValidServerId_Returns404:测试DELETE api/Server/:serverId,使用无效的 serverId(如 0)应返回 404。
Postman testing:
For API testing, I include the header in requests in Postman. You can use a .csv file with the same name as your environment collections to replace the error message for different languages. I updated the utils.CheckRequired function to validate the field and the custom error message that previously was only “Required”.
Postman 测试:
在 API 测试中,我在 Postman 的请求中包含了请求头。你可以使用与环境集合同名的 .csv 文件来替换不同语言的错误消息。我更新了 utils.CheckRequired 函数以验证字段,并支持自定义错误消息(之前仅支持“Required”)。
I added a Pre-request script in the servers folder with code to log in as an admin user and set the Bearer token. With this approach, when you make any request in the Servers folder, you have a valid token. If not, you first need to run the admin login request to get a valid token. 我在 servers 文件夹中添加了一个 Pre-request 脚本,用于以管理员身份登录并设置 Bearer 令牌。通过这种方式,当你在 Servers 文件夹中发起任何请求时,都会拥有有效的令牌。如果未获取,则需要先运行管理员登录请求以获取有效令牌。
// Login as Admin and store the AccessToken
const loginUrl = pm.environment.get("AuthAPI") + "/api/users/login";
const loginBody = {
Company: pm.environment.get("company"),
UserName: pm.environment.get("userNameAdmin"),
Password: pm.environment.get("passwordAdmin"),
Language: pm.environment.get("language")
};
pm.sendRequest({
url: loginUrl,
method: "POST",
header: { "Content-Type": "application/json" },
body: { mode: "raw", raw: JSON.stringify(loginBody) }
}, function (err, response) {
if (err) {
console.error("Login failed:", err);
} else {
const jsonData = response.json();
pm.collectionVariables.set("AccessTokenAdmin", jsonData.AccessToken);
console.log("AccessTokenAdmin set successfully");
}
});
To test the POST, I created collection variables with random data. 为了测试 POST,我创建了包含随机数据的集合变量。
const randomName = pm.variables.replaceIn('{{$randomProductName}}');
const randomUrl = pm.variables.replaceIn('{{$randomUrl}}');
const randomKey = Math.floor(Math.random() * (999 - 2 + 1)) + 2;
pm.collectionVariables.set("serverKey", randomKey);
pm.collectionVariables.set("serverName", randomName);
pm.collectionVariables.set("serverUrl", randomUrl);
And I checked the server values in the Post-response: 并在 Post-response 中检查了服务器值:
const response = pm.response.json();
utils.StatusCreated();
const serverKey = pm.collectionVariables.get("serverKey")
const serverName = pm.collectionVariables.get("serverName")
const serverUrl = pm.collectionVariables.get("serverUrl")
pm.test("Server key is: " + serverKey, function() { pm.expect(response.Key).to.eq(serverKey) })
pm.test("Server name is: " + serverName, function() { pm.expect(response.Name).to.eq(serverName) })
pm.test("Server Url is: " + serverUrl, function() { pm.expect(response.Url).to.eq(serverUrl) })
pm.test("Server Active is: true", function() { pm.expect(response.Active).to.be.true; })
pm.collectionVariables.set("serverId", response.Id)
If you want to validate the JSON Schema of the response, you can use the jsonschema function:
如果你想验证响应的 JSON Schema,可以使用 jsonschema 函数:
const schema = {
type: "array",
minItems: 1,
additionalProperties: false,
items: { required: ["Id","Key", "Name", "Url", "Active"] }
}