-
Notifications
You must be signed in to change notification settings - Fork 0
Implement JSON plan parsing and text formatting (Iteration 2) #12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
a075ee8
edb297d
3d1d189
ae75133
07826eb
1d2d688
35eb957
9417871
05bb272
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -7,7 +7,8 @@ | |||||||
| "defaultBranch": "main" | ||||||||
| }, | ||||||||
| "files": { | ||||||||
| "ignoreUnknown": false | ||||||||
| "ignoreUnknown": false, | ||||||||
| "includes": ["**/*.ts", "**/*.js", "**/*.json", "!fixtures"] | ||||||||
|
||||||||
| "includes": ["**/*.ts", "**/*.js", "**/*.json", "!fixtures"] | |
| "includes": ["**/*.ts", "**/*.js", "**/*.json"], | |
| "ignore": ["fixtures/**"] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,175 @@ | ||
| import { readFile } from "node:fs/promises"; | ||
| import { describe, expect, it } from "vitest"; | ||
| import { ParsePlanUseCase } from "../src/domain/usecases/ParsePlanUseCase"; | ||
| import { TextFormatterUseCase } from "../src/domain/usecases/TextFormatterUseCase"; | ||
|
|
||
| describe("E2E: JSON Parsing", () => { | ||
| describe("Plan parsing", () => { | ||
| it("should parse a plan with no changes", async () => { | ||
| const content = await readFile("./fixtures/sample-plan.json", "utf-8"); | ||
| const parser = new ParsePlanUseCase(); | ||
|
|
||
| const plan = await parser.parse(content); | ||
|
|
||
| expect(plan.resourceChanges).toHaveLength(0); | ||
| }); | ||
|
|
||
| it("should parse a plan with additions", async () => { | ||
| const content = await readFile( | ||
| "./fixtures/plan-with-changes.json", | ||
| "utf-8", | ||
| ); | ||
| const parser = new ParsePlanUseCase(); | ||
|
|
||
| const plan = await parser.parse(content); | ||
|
|
||
| expect(plan.resourceChanges).toHaveLength(1); | ||
| expect(plan.resourceChanges[0].actions).toContain("create"); | ||
| }); | ||
|
|
||
| it("should parse a plan with updates", async () => { | ||
| const content = await readFile( | ||
| "./fixtures/plan-with-updates.json", | ||
| "utf-8", | ||
| ); | ||
| const parser = new ParsePlanUseCase(); | ||
|
|
||
| const plan = await parser.parse(content); | ||
|
|
||
| expect(plan.resourceChanges).toHaveLength(1); | ||
| expect(plan.resourceChanges[0].actions).toContain("update"); | ||
| }); | ||
|
|
||
| it("should parse a plan with deletions", async () => { | ||
| const content = await readFile( | ||
| "./fixtures/plan-with-deletions.json", | ||
| "utf-8", | ||
| ); | ||
| const parser = new ParsePlanUseCase(); | ||
|
|
||
| const plan = await parser.parse(content); | ||
|
|
||
| expect(plan.resourceChanges).toHaveLength(1); | ||
| expect(plan.resourceChanges[0].actions).toContain("delete"); | ||
| }); | ||
|
|
||
| it("should parse a plan with mixed changes", async () => { | ||
| const content = await readFile( | ||
| "./fixtures/plan-with-mixed-changes.json", | ||
| "utf-8", | ||
| ); | ||
| const parser = new ParsePlanUseCase(); | ||
|
|
||
| const plan = await parser.parse(content); | ||
|
|
||
| expect(plan.resourceChanges).toHaveLength(3); | ||
|
|
||
| const creates = plan.resourceChanges.filter((rc) => | ||
| rc.actions.includes("create"), | ||
| ); | ||
| const updates = plan.resourceChanges.filter((rc) => | ||
| rc.actions.includes("update"), | ||
| ); | ||
| const deletes = plan.resourceChanges.filter((rc) => | ||
| rc.actions.includes("delete"), | ||
| ); | ||
|
|
||
| expect(creates).toHaveLength(1); | ||
| expect(updates).toHaveLength(1); | ||
| expect(deletes).toHaveLength(1); | ||
| }); | ||
|
|
||
| it("should reject malformed JSON with descriptive error", async () => { | ||
| const content = await readFile("./fixtures/malformed-plan.json", "utf-8"); | ||
| const parser = new ParsePlanUseCase(); | ||
|
|
||
| await expect(parser.parse(content)).rejects.toThrow( | ||
| "Invalid JSON in plan file", | ||
| ); | ||
| }); | ||
| }); | ||
|
|
||
| describe("Text formatting", () => { | ||
| it("should format a plan with no changes", async () => { | ||
| const content = await readFile("./fixtures/sample-plan.json", "utf-8"); | ||
| const parser = new ParsePlanUseCase(); | ||
| const formatter = new TextFormatterUseCase(); | ||
|
|
||
| const plan = await parser.parse(content); | ||
| const result = formatter.format(plan); | ||
|
|
||
| expect(result).toContain("No changes"); | ||
| expect(result).toContain("0 to add"); | ||
| expect(result).toContain("0 to change"); | ||
| expect(result).toContain("0 to destroy"); | ||
| }); | ||
|
|
||
| it("should format a plan with additions", async () => { | ||
| const content = await readFile( | ||
| "./fixtures/plan-with-changes.json", | ||
| "utf-8", | ||
| ); | ||
| const parser = new ParsePlanUseCase(); | ||
| const formatter = new TextFormatterUseCase(); | ||
|
|
||
| const plan = await parser.parse(content); | ||
| const result = formatter.format(plan); | ||
|
|
||
| expect(result).toContain("1 to add"); | ||
| expect(result).toContain("aws_s3_bucket.example"); | ||
| expect(result).toContain("create"); | ||
| }); | ||
|
|
||
| it("should format a plan with updates", async () => { | ||
| const content = await readFile( | ||
| "./fixtures/plan-with-updates.json", | ||
| "utf-8", | ||
| ); | ||
| const parser = new ParsePlanUseCase(); | ||
| const formatter = new TextFormatterUseCase(); | ||
|
|
||
| const plan = await parser.parse(content); | ||
| const result = formatter.format(plan); | ||
|
|
||
| expect(result).toContain("1 to change"); | ||
| expect(result).toContain("aws_s3_bucket.updated"); | ||
| expect(result).toContain("update"); | ||
| }); | ||
|
|
||
| it("should format a plan with deletions", async () => { | ||
| const content = await readFile( | ||
| "./fixtures/plan-with-deletions.json", | ||
| "utf-8", | ||
| ); | ||
| const parser = new ParsePlanUseCase(); | ||
| const formatter = new TextFormatterUseCase(); | ||
|
|
||
| const plan = await parser.parse(content); | ||
| const result = formatter.format(plan); | ||
|
|
||
| expect(result).toContain("1 to destroy"); | ||
| expect(result).toContain("aws_s3_bucket.deleted"); | ||
| expect(result).toContain("delete"); | ||
| }); | ||
|
|
||
| it("should format a plan with mixed changes", async () => { | ||
| const content = await readFile( | ||
| "./fixtures/plan-with-mixed-changes.json", | ||
| "utf-8", | ||
| ); | ||
| const parser = new ParsePlanUseCase(); | ||
| const formatter = new TextFormatterUseCase(); | ||
|
|
||
| const plan = await parser.parse(content); | ||
| const result = formatter.format(plan); | ||
|
|
||
| expect(result).toContain("1 to add"); | ||
| expect(result).toContain("1 to change"); | ||
| expect(result).toContain("1 to destroy"); | ||
|
|
||
| expect(result).toContain("aws_s3_bucket.new"); | ||
| expect(result).toContain("aws_s3_bucket.updated"); | ||
| expect(result).toContain("aws_s3_bucket.deleted"); | ||
| }); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| { invalid json } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| { | ||
| "format_version": "1.0", | ||
| "terraform_version": "1.5.0", | ||
| "planned_values": { | ||
| "root_module": { | ||
| "resources": [] | ||
| } | ||
| }, | ||
| "resource_changes": [ | ||
| { | ||
| "address": "aws_s3_bucket.deleted", | ||
| "mode": "managed", | ||
| "type": "aws_s3_bucket", | ||
| "name": "deleted", | ||
| "change": { | ||
| "actions": ["delete"], | ||
| "before": { | ||
| "bucket": "old-bucket", | ||
| "acl": "private" | ||
| }, | ||
| "after": null | ||
| } | ||
| } | ||
| ], | ||
| "configuration": {} | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,57 @@ | ||
| { | ||
| "format_version": "1.0", | ||
| "terraform_version": "1.5.0", | ||
| "planned_values": { | ||
| "root_module": { | ||
| "resources": [] | ||
| } | ||
| }, | ||
| "resource_changes": [ | ||
| { | ||
| "address": "aws_s3_bucket.new", | ||
| "mode": "managed", | ||
| "type": "aws_s3_bucket", | ||
| "name": "new", | ||
| "change": { | ||
| "actions": ["create"], | ||
| "before": null, | ||
| "after": { | ||
| "bucket": "new-bucket", | ||
| "acl": "private" | ||
| } | ||
| } | ||
| }, | ||
| { | ||
| "address": "aws_s3_bucket.updated", | ||
| "mode": "managed", | ||
| "type": "aws_s3_bucket", | ||
| "name": "updated", | ||
| "change": { | ||
| "actions": ["update"], | ||
| "before": { | ||
| "bucket": "existing-bucket", | ||
| "acl": "private" | ||
| }, | ||
| "after": { | ||
| "bucket": "existing-bucket", | ||
| "acl": "public-read" | ||
| } | ||
| } | ||
| }, | ||
| { | ||
| "address": "aws_s3_bucket.deleted", | ||
| "mode": "managed", | ||
| "type": "aws_s3_bucket", | ||
| "name": "deleted", | ||
| "change": { | ||
| "actions": ["delete"], | ||
| "before": { | ||
| "bucket": "old-bucket", | ||
| "acl": "private" | ||
| }, | ||
| "after": null | ||
| } | ||
| } | ||
| ], | ||
| "configuration": {} | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| { | ||
| "format_version": "1.0", | ||
| "terraform_version": "1.5.0", | ||
| "planned_values": { | ||
| "root_module": { | ||
| "resources": [] | ||
| } | ||
| }, | ||
| "resource_changes": [ | ||
| { | ||
| "address": "aws_s3_bucket.updated", | ||
| "mode": "managed", | ||
| "type": "aws_s3_bucket", | ||
| "name": "updated", | ||
| "change": { | ||
| "actions": ["update"], | ||
| "before": { | ||
| "bucket": "my-bucket", | ||
| "acl": "private" | ||
| }, | ||
| "after": { | ||
| "bucket": "my-bucket", | ||
| "acl": "public-read" | ||
| } | ||
| } | ||
| } | ||
| ], | ||
| "configuration": {} | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| import type { Plan } from "../entities/Plan"; | ||
|
|
||
| export interface ITextFormatter { | ||
| format(plan: Plan): string; | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.