Coverage for test\test_cors.py: 100%

1# test_cors_with_app.py

2 import pytest

3 from nexios import get_application

4 from nexios.testing import Client

5 from nexios.config import MakeConfig

6 from nexios.middlewares.cors import CORSMiddleware

7

8

9@pytest.fixture

10 async def cors_app():

11 # Create app with CORS configuration

12 config = MakeConfig(

13 {

14 "cors": {

15 "allow_origins": ["http://example.com", "https://example.org"],

16 "allow_methods": ["GET", "POST"],

17 "allow_headers": ["X-Custom-Header"],

18 "allow_credentials": True,

19 "expose_headers": ["X-Exposed-Header"],

20 "debug": True,

21 }

22 }

23 )

24 app = get_application(config)

25

26 # Add test route

27 @app.get("/test")

28 async def test_route(req, res):

29 return res.text("OK")

30

31 # Add CORS middleware

32 app.add_middleware(CORSMiddleware())

33

34 return app

35

36

37@pytest.fixture

38 async def client(cors_app):

39 async with Client(cors_app) as c:

40 yield c

41

42

43 async def test_simple_request_allowed_origin(client):

44 # Test simple GET request with allowed origin

45 response = await client.get("/test", headers={"Origin": "http://example.com"})

46

47 assert response.status_code == 200

48 assert response.text == "OK"

49 assert response.headers["Access-Control-Allow-Origin"] == "http://example.com"

50 assert response.headers["Access-Control-Allow-Credentials"] == "true"

51 assert response.headers["Access-Control-Expose-Headers"] == "X-Exposed-Header"

52

53

54 async def test_simple_request_disallowed_origin(client):

55 # Test simple GET request with disallowed origin

56 response = await client.get("/test", headers={"Origin": "http://disallowed.com"})

57

58 assert response.status_code == 200

59 assert response.text == "OK"

60 # Should not have CORS headers for disallowed origin

61 assert "Access-Control-Allow-Origin" not in response.headers

62

63

64 async def test_preflight_request_success(client):

65 # Test successful OPTIONS preflight request

66 response = await client.options(

67 "/test",

68 headers={

69 "Origin": "http://example.com",

70 "Access-Control-Request-Method": "GET",

71 "Access-Control-Request-Headers": "X-Custom-Header",

72 },

73 )

74

75 assert response.status_code == 201 # Custom status from our middleware

76 assert response.headers["Access-Control-Allow-Origin"] == "http://example.com"

77 assert response.headers["Access-Control-Allow-Methods"] == "GET, POST"

78 assert response.headers["Access-Control-Allow-Headers"] == "X-Custom-Header"

79 assert response.headers["Access-Control-Allow-Credentials"] == "true"

80 assert response.headers["Access-Control-Max-Age"] == "600" # Default value

81

82

83 async def test_preflight_request_disallowed_method(client):

84 # Test OPTIONS request with disallowed method

85 response = await client.options(

86 "/test",

87 headers={

88 "Origin": "http://example.com",

89 "Access-Control-Request-Method": "PUT",

90 },

91 )

92

93 # assert response.status_code == 400 # Default error status

94 assert "PUT" not in response.headers.get("Access-Control-Allow-Methods", "")

95

96

97 async def test_preflight_request_disallowed_header(client):

98 # Test OPTIONS request with disallowed header

99 response = await client.options(

100 "/test",

101 headers={

102 "Origin": "http://example.com",

103 "Access-Control-Request-Method": "GET",

104 "Access-Control-Request-Headers": "X-Disallowed-Header",

105 },

106 )

107

108 assert response.status_code == 400

109 assert "X-Disallowed-Header" not in response.headers.get(

110 "Access-Control-Allow-Headers", ""

111 )

112

113

114 async def test_wildcard_origin():

115 # Test app with wildcard origin

116 config = MakeConfig({"cors": {"allow_origins": ["*"], "allow_methods": ["*"]}})

117 app = get_application(config)

118

119 @app.get("/wildcard")

120 async def wildcard_route(req, res):

121 return res.text("OK")

122

123 app.add_middleware(CORSMiddleware())

124

125 async with Client(app) as client:

126 response = await client.get(

127 "/wildcard", headers={"Origin": "http://any-origin.com"}

128 )

129

130 assert response.status_code == 200

131 assert (

132 response.headers["Access-Control-Allow-Origin"] == "http://any-origin.com"

133 )

134

135

136 async def test_no_cors_headers_without_origin():

137 # Test that CORS headers aren't added when no Origin header is present

138 config = MakeConfig(

139 {"cors": {"allow_origins": ["http://example.com"], "allow_methods": ["GET"]}}

140 )

141 app = get_application(config)

142

143 @app.get("/no-origin")

144 async def no_origin_route(req, res):

145 return res.text("OK")

146

147 app.add_middleware(CORSMiddleware())

148

149 async with Client(app) as client:

150 response = await client.get("/no-origin")

151

152 assert response.status_code == 200

153 assert "Access-Control-Allow-Origin" not in response.headers