@@ -960,75 +960,182 @@ class Uploader {
960
960
961
961
NOTE: Using [ Direct Uploads] ( #direct-uploads ) can sometimes result in a file that uploads, but never attaches to a record. Consider [ purging unattached uploads] ( #purging-unattached-uploads ) .
962
962
963
- Discarding Files Stored During System Tests
963
+ Testing
964
964
-------------------------------------------
965
965
966
- System tests clean up test data by rolling back a transaction. Because destroy
966
+ Use [ ` fixture_file_upload ` ] [ ] to test uploading a file in an integration or controller test.
967
+ Rails handles files like any other parameter.
968
+
969
+ ``` ruby
970
+ class SignupController < ActionDispatch ::IntegrationTest
971
+ test " can sign up" do
972
+ post signup_path, params: {
973
+ name: " David" ,
974
+ avatar: fixture_file_upload(" david.png" , " image/png" )
975
+ }
976
+
977
+ user = User .order(:created_at ).last
978
+ assert user.avatar.attached?
979
+ end
980
+ end
981
+ ```
982
+
983
+ [ `fixture_file_upload` ] : https://api.rubyonrails.org/classes/ActionDispatch/TestProcess/FixtureFile.html
984
+
985
+ ### Discarding files created during tests
986
+
987
+ #### System tests
988
+
989
+ System tests clean up test data by rolling back a transaction. Because ` destroy `
967
990
is never called on an object, the attached files are never cleaned up. If you
968
991
want to clear the files, you can do it in an ` after_teardown ` callback. Doing it
969
992
here ensures that all connections created during the test are complete and
970
993
you won't receive an error from Active Storage saying it can't find a file.
971
994
972
995
``` ruby
973
996
class ApplicationSystemTestCase < ActionDispatch ::SystemTestCase
974
- driven_by :selenium , using: :chrome , screen_size: [1400 , 1400 ]
975
-
976
- def remove_uploaded_files
977
- FileUtils .rm_rf(" #{ Rails .root} /storage_test" )
978
- end
979
-
997
+ # ...
980
998
def after_teardown
981
999
super
982
- remove_uploaded_files
1000
+ FileUtils .rm_rf(ActiveStorage ::Blob .service.root)
1001
+ end
1002
+ # ...
1003
+ end
1004
+ ```
1005
+
1006
+ If you're using [ parallel tests] [ ] and the ` DiskService ` , you should configure each process to use its own
1007
+ folder for Active Storage. This way, the ` teardown ` callback will only delete files from the relevant process'
1008
+ tests.
1009
+
1010
+ ``` ruby
1011
+ class ApplicationSystemTestCase < ActionDispatch ::SystemTestCase
1012
+ # ...
1013
+ parallelize_setup do |i |
1014
+ ActiveStorage ::Blob .service.root = " #{ ActiveStorage ::Blob .service.root} -#{ i } "
983
1015
end
1016
+ # ...
984
1017
end
985
1018
```
986
1019
987
1020
If your system tests verify the deletion of a model with attachments and you're
988
1021
using Active Job, set your test environment to use the inline queue adapter so
989
1022
the purge job is executed immediately rather at an unknown time in the future.
990
1023
991
- You may also want to use a separate service definition for the test environment
992
- so your tests don't delete the files you create during development.
993
-
994
1024
``` ruby
995
1025
# Use inline job processing to make things happen immediately
996
1026
config.active_job.queue_adapter = :inline
997
-
998
- # Separate file storage in the test environment
999
- config.active_storage.service = :local_test
1000
1027
```
1001
1028
1002
- Discarding Files Stored During Integration Tests
1003
- -------------------------------------------
1029
+ [ parallel tests ] : https://guides.rubyonrails.org/testing.html#parallel-testing
1030
+
1031
+ #### Integration tests
1004
1032
1005
1033
Similarly to System Tests, files uploaded during Integration Tests will not be
1006
1034
automatically cleaned up. If you want to clear the files, you can do it in an
1007
- ` after_teardown ` callback. Doing it here ensures that all connections created
1008
- during the test are complete and you won't receive an error from Active Storage
1009
- saying it can't find a file.
1035
+ ` teardown ` callback.
1010
1036
1011
1037
``` ruby
1012
- module RemoveUploadedFiles
1038
+ class ActionDispatch :: IntegrationTest
1013
1039
def after_teardown
1014
1040
super
1015
- remove_uploaded_files
1041
+ FileUtils .rm_rf( ActiveStorage :: Blob .service.root)
1016
1042
end
1043
+ end
1044
+ ```
1017
1045
1018
- private
1046
+ If you're using [ parallel tests] [ ] and the Disk service, you should configure each process to use its own
1047
+ folder for Active Storage. This way, the ` teardown ` callback will only delete files from the relevant process'
1048
+ tests.
1049
+
1050
+ ``` ruby
1051
+ class ActionDispatch ::IntegrationTest
1052
+ parallelize_setup do |i |
1053
+ ActiveStorage ::Blob .service.root = " #{ ActiveStorage ::Blob .service.root} -#{ i } "
1054
+ end
1055
+ end
1056
+ ```
1057
+
1058
+ [ parallel tests ] : https://guides.rubyonrails.org/testing.html#parallel-testing
1059
+
1060
+ ### Adding attachments to fixtures
1061
+
1062
+ You can add attachments to your existing [ fixtures] [ ] . First, you'll want to create a separate storage service:
1063
+
1064
+ ``` yml
1065
+ # config/storage.yml
1066
+
1067
+ test_fixtures :
1068
+ service : Disk
1069
+ root : <%= Rails.root.join("tmp/storage_fixtures") %>
1070
+ ` ` `
1071
+
1072
+ This tells Active Storage where to "upload" fixture files to, so it should be a temporary directory. By making it
1073
+ a different directory to your regular ` test` service, you can separate fixture files from files uploaded during a
1074
+ test.
1075
+
1076
+ Next, create fixture files for the Active Storage classes :
1077
+
1078
+ ` ` ` yml
1079
+ # active_storage/attachments.yml
1080
+ david_avatar:
1081
+ name: avatar
1082
+ record: david (User)
1083
+ blob: david_avatar_blob
1084
+ ` ` `
1085
+
1086
+ ` ` ` yml
1087
+ # active_storage/blobs.yml
1088
+ david_avatar_blob: <%= ActiveStorage::FixtureSet.blob filename: "david.png", service_name: "test_fixtures" % >
1089
+ ` ` `
1090
+
1091
+ Then put a file in your fixtures directory (the default path is `test/fixtures/files`) with the corresponding filename.
1092
+ See the [`ActiveStorage::FixtureSet`][] docs for more information.
1019
1093
1020
- def remove_uploaded_files
1021
- FileUtils .rm_rf(Rails .root.join(' tmp' , ' storage' ))
1094
+ Once everything is set up, you'll be able to access attachments in your tests :
1095
+
1096
+ ` ` ` ruby
1097
+ class UserTest < ActiveSupport::TestCase
1098
+ def test_avatar
1099
+ avatar = users(:david).avatar
1100
+
1101
+ assert avatar.attached?
1102
+ assert_not_nil avatar.download
1103
+ assert_equal 1000, avatar.byte_size
1022
1104
end
1023
1105
end
1106
+ ` ` `
1107
+
1108
+ # ### Cleaning up fixtures
1024
1109
1025
- module ActionDispatch
1026
- class IntegrationTest
1027
- prepend RemoveUploadedFiles
1110
+ While files uploaded in tests are cleaned up [at the end of each test](#discarding-files-created-during-tests),
1111
+ you only need to clean up fixture files once : when all your tests complete.
1112
+
1113
+ If you're using parallel tests, call `parallelize_teardown` :
1114
+
1115
+ ` ` ` ruby
1116
+ class ActiveSupport::TestCase
1117
+ # ...
1118
+ parallelize_teardown do |i|
1119
+ FileUtils.rm_rf(ActiveStorage::Blob.services.fetch(:test_fixtures).root)
1028
1120
end
1121
+ # ...
1122
+ end
1123
+ ` ` `
1124
+
1125
+ If you're not running parallel tests, use `Minitest.after_run` or the equivalent for your test
1126
+ framework (eg. `after(:suite)` for RSpec) :
1127
+
1128
+ ` ` ` ruby
1129
+ # test_helper.rb
1130
+
1131
+ Minitest.after_run do
1132
+ FileUtils.rm_rf(ActiveStorage::Blob.services.fetch(:test_fixtures).root)
1029
1133
end
1030
1134
` ` `
1031
1135
1136
+ [fixtures] : https://guides.rubyonrails.org/testing.html#the-low-down-on-fixtures
1137
+ [`ActiveStorage::FixtureSet`] : https://api.rubyonrails.org/classes/ActiveStorage/FixtureSet.html
1138
+
1032
1139
Implementing Support for Other Cloud Services
1033
1140
---------------------------------------------
1034
1141
0 commit comments