Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
d32dc2f
test: add unit tests for apps/channel-rules commands
AndyTWF Dec 8, 2025
7cb4dd5
test: add unit test for apps/current
AndyTWF Dec 8, 2025
d591869
test: add unit test for apps/logs/history
AndyTWF Dec 8, 2025
ddb4a9d
test: add unit test for apps/logs/subscribe
AndyTWF Dec 8, 2025
181e356
test: add unit test for apps/set-apns-p12
AndyTWF Dec 8, 2025
5bb20b1
test: add unit test for auth/keys/current
AndyTWF Dec 8, 2025
76c2f4d
test: add unit test for auth/keys/get
AndyTWF Dec 8, 2025
71b4fd0
test: add unit test for auth/keys/list
AndyTWF Dec 8, 2025
99afaac
test: add unit test for auth/keys/revoke
AndyTWF Dec 8, 2025
5b43390
test: add unit test for auth/keys/update
AndyTWF Dec 8, 2025
823a992
test: add unit test for channel-rule/create
AndyTWF Dec 8, 2025
e6efebc
test: add unit test for channel-rule/delete
AndyTWF Dec 8, 2025
65bc7ea
test: add unit test for channel-rule/list
AndyTWF Dec 8, 2025
bc0b802
test: add unit test for channel-rule/update
AndyTWF Dec 8, 2025
af26310
test: add unit test for config/path
AndyTWF Dec 8, 2025
a620da5
test: add unit test for logs/app/subscribe
AndyTWF Dec 8, 2025
4841dbe
test: add unit test for logs/channel-lifecycle/subscribe
AndyTWF Dec 8, 2025
6238ea3
test: add unit test for logs/connection-lifecycle/history
AndyTWF Dec 8, 2025
9bd7a72
test: add unit test for logs/push/history
AndyTWF Dec 8, 2025
16c797d
test: add unit test for rooms/messages/reactions/remove
AndyTWF Dec 8, 2025
c9527ec
test: add unit test for rooms/messages/reactions/send
AndyTWF Dec 8, 2025
29258e5
test: add unit test for rooms/messages/reactions/subscribe
AndyTWF Dec 8, 2025
eda3314
test: add unit test for rooms/presence/subscribe
AndyTWF Dec 8, 2025
f023215
test: add unit test for rooms/reactions/subscribe
AndyTWF Dec 8, 2025
45473e0
test: add unit test for rooms/typing/subscribe
AndyTWF Dec 8, 2025
2cc6b57
test: add unit test for spaces/locations/get-all
AndyTWF Dec 8, 2025
e076d58
test: add unit test for spaces/locks/get
AndyTWF Dec 8, 2025
a13c908
test: add unit test for spaces/locks/get-all
AndyTWF Dec 8, 2025
55e2b67
test: remove ABLY_API_KEY from test environment
AndyTWF Dec 10, 2025
b8b72b4
test: add unit test for apps/update
AndyTWF Dec 10, 2025
03c9c5e
test: add unit test for auth/issue-ably-token
AndyTWF Dec 10, 2025
43f20f0
test: add unit test for auth/issue-jwt-token
AndyTWF Dec 10, 2025
e394e2f
test: add unit test for channels/occupancy/subscribe
AndyTWF Dec 10, 2025
a881f81
test: add unit test for config/show
AndyTWF Dec 10, 2025
973fc9e
test: add unit test for integrations/create
AndyTWF Dec 10, 2025
00c1a86
test: add unit tests for integrations/delete, integrations/get, and i…
AndyTWF Dec 10, 2025
c59dbb4
test: add unit test for logs/channel-lifecycle
AndyTWF Dec 10, 2025
7e7fccf
test: add unit test for spaces/cursors/get-all
AndyTWF Dec 10, 2025
24f8ffb
test: add unit test for spaces/cursors/subscribe
AndyTWF Dec 10, 2025
336b1e7
test: add unit test for spaces/locations/subscribe
AndyTWF Dec 10, 2025
e67323c
test: add unit test for spaces/locks/subscribe
AndyTWF Dec 10, 2025
4bd7556
test: run in sequence temporarily due to config bug
AndyTWF Dec 11, 2025
b588726
test: tighten assertions in auth/revoke-token test
AndyTWF Dec 12, 2025
e12bea1
test: tighten assertions in channels/list test
AndyTWF Dec 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/commands/logs/channel-lifecycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export default class LogsChannelLifecycle extends AblyBaseCommand {
this.log("");
});

// Wait until interrupted
await waitUntilInterruptedOrTimeout();
} catch (error: unknown) {
const err = error as Error;
Expand Down
242 changes: 242 additions & 0 deletions test/unit/commands/apps/channel-rules/create.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
import { describe, it, expect, beforeEach, afterEach } from "vitest";
import { runCommand } from "@oclif/test";
import nock from "nock";
import { resolve } from "node:path";
import { mkdirSync, writeFileSync, existsSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";

describe("apps:channel-rules:create command", () => {
const mockAccessToken = "fake_access_token";
const mockAccountId = "test-account-id";
const mockAppId = "550e8400-e29b-41d4-a716-446655440000";
const mockRuleName = "chat";
const mockRuleId = "chat";
let testConfigDir: string;
let originalConfigDir: string;

beforeEach(() => {
process.env.ABLY_ACCESS_TOKEN = mockAccessToken;

testConfigDir = resolve(tmpdir(), `ably-cli-test-${Date.now()}`);
mkdirSync(testConfigDir, { recursive: true, mode: 0o700 });

originalConfigDir = process.env.ABLY_CLI_CONFIG_DIR || "";
process.env.ABLY_CLI_CONFIG_DIR = testConfigDir;

const configContent = `[current]
account = "default"

[accounts.default]
accessToken = "${mockAccessToken}"
accountId = "${mockAccountId}"
accountName = "Test Account"
userEmail = "test@example.com"
currentAppId = "${mockAppId}"
`;
writeFileSync(resolve(testConfigDir, "config"), configContent);
});

afterEach(() => {
nock.cleanAll();
delete process.env.ABLY_ACCESS_TOKEN;

if (originalConfigDir) {
process.env.ABLY_CLI_CONFIG_DIR = originalConfigDir;
} else {
delete process.env.ABLY_CLI_CONFIG_DIR;
}

if (existsSync(testConfigDir)) {
rmSync(testConfigDir, { recursive: true, force: true });
}
});

describe("successful channel rule creation", () => {
it("should create a channel rule successfully", async () => {
nock("https://control.ably.net")
.post(`/v1/apps/${mockAppId}/namespaces`)
.reply(201, {
id: mockRuleId,
persisted: false,
pushEnabled: false,
created: Date.now(),
modified: Date.now(),
});

const { stdout } = await runCommand(
[
"apps:channel-rules:create",
"--name",
mockRuleName,
"--app",
mockAppId,
],
import.meta.url,
);

expect(stdout).toContain("Channel rule created successfully");
expect(stdout).toContain(mockRuleId);
});

it("should create a channel rule with persisted flag", async () => {
nock("https://control.ably.net")
.post(`/v1/apps/${mockAppId}/namespaces`, (body) => {
return body.persisted === true;
})
.reply(201, {
id: mockRuleId,
persisted: true,
pushEnabled: false,
created: Date.now(),
modified: Date.now(),
});

const { stdout } = await runCommand(
[
"apps:channel-rules:create",
"--name",
mockRuleName,
"--app",
mockAppId,
"--persisted",
],
import.meta.url,
);

expect(stdout).toContain("Channel rule created successfully");
expect(stdout).toContain("Persisted: Yes");
});

it("should create a channel rule with push-enabled flag", async () => {
nock("https://control.ably.net")
.post(`/v1/apps/${mockAppId}/namespaces`, (body) => {
return body.pushEnabled === true;
})
.reply(201, {
id: mockRuleId,
persisted: false,
pushEnabled: true,
created: Date.now(),
modified: Date.now(),
});

const { stdout } = await runCommand(
[
"apps:channel-rules:create",
"--name",
mockRuleName,
"--app",
mockAppId,
"--push-enabled",
],
import.meta.url,
);

expect(stdout).toContain("Channel rule created successfully");
expect(stdout).toContain("Push Enabled: Yes");
});

it("should output JSON format when --json flag is used", async () => {
const mockRule = {
id: mockRuleId,
persisted: false,
pushEnabled: false,
created: Date.now(),
modified: Date.now(),
};

nock("https://control.ably.net")
.post(`/v1/apps/${mockAppId}/namespaces`)
.reply(201, mockRule);

const { stdout } = await runCommand(
[
"apps:channel-rules:create",
"--name",
mockRuleName,
"--app",
mockAppId,
"--json",
],
import.meta.url,
);

const result = JSON.parse(stdout);
expect(result).toHaveProperty("success", true);
expect(result).toHaveProperty("rule");
expect(result.rule).toHaveProperty("id", mockRuleId);
});
});

describe("error handling", () => {
it("should require name parameter", async () => {
const { error } = await runCommand(
["apps:channel-rules:create", "--app", mockAppId],
import.meta.url,
);

expect(error).toBeDefined();
expect(error!.message).toMatch(/Missing required flag.*name/);
});

it("should handle 401 authentication error", async () => {
nock("https://control.ably.net")
.post(`/v1/apps/${mockAppId}/namespaces`)
.reply(401, { error: "Unauthorized" });

const { error } = await runCommand(
[
"apps:channel-rules:create",
"--name",
mockRuleName,
"--app",
mockAppId,
],
import.meta.url,
);

expect(error).toBeDefined();
expect(error!.message).toMatch(/401/);
});

it("should handle 400 validation error", async () => {
nock("https://control.ably.net")
.post(`/v1/apps/${mockAppId}/namespaces`)
.reply(400, { error: "Validation failed" });

const { error } = await runCommand(
[
"apps:channel-rules:create",
"--name",
mockRuleName,
"--app",
mockAppId,
],
import.meta.url,
);

expect(error).toBeDefined();
expect(error!.message).toMatch(/400/);
});

it("should handle network errors", async () => {
nock("https://control.ably.net")
.post(`/v1/apps/${mockAppId}/namespaces`)
.replyWithError("Network error");

const { error } = await runCommand(
[
"apps:channel-rules:create",
"--name",
mockRuleName,
"--app",
mockAppId,
],
import.meta.url,
);

expect(error).toBeDefined();
expect(error!.message).toMatch(/Network error/);
});
});
});
Loading
Loading